git.s-ol.nu forks/DiligentTools / e0c42a0
Updated tiny gltf assiduous 2 years ago
1 changed file(s) with 3398 addition(s) and 1241 deletion(s). Raw diff Collapse all Expand all
33 //
44 // The MIT License (MIT)
55 //
6 // Copyright (c) 2015 - 2019 Syoyo Fujita, Aurélien Chatelain and many
6 // Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many
77 // contributors.
88 //
99 // Permission is hereby granted, free of charge, to any person obtaining a copy
2525 // THE SOFTWARE.
2626
2727 // Version:
28 // - v2.4.1 Fix some glTF object class does not have `extensions` and/or
29 // `extras` property.
30 // - v2.4.0 Experimental RapidJSON and C++14 support(Thanks to @jrkoone).
31 // - v2.3.1 Set default value of minFilter and magFilter in Sampler to -1.
32 // - v2.3.0 Modified Material representation according to glTF 2.0 schema
33 // (and introduced TextureInfo class)
34 // Change the behavior of `Value::IsNumber`. It return true either the
35 // value is int or real.
2836 // - v2.2.0 Add loading 16bit PNG support. Add Sparse accessor support(Thanks
2937 // to @Ybalrid)
3038 // - v2.1.0 Add draco compression.
4553 #include <cstdint>
4654 #include <cstdlib>
4755 #include <cstring>
56 #include <limits>
4857 #include <map>
4958 #include <string>
5059 #include <vector>
5160
61 #ifndef TINYGLTF_USE_CPP14
62 #include <functional>
63 #endif
64
5265 #ifdef __ANDROID__
5366 #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
5467 #include <android/asset_manager.h>
5568 #endif
5669 #endif
70
71 #ifdef __GNUC__
72 #if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 8))
73 #define TINYGLTF_NOEXCEPT
74 #else
75 #define TINYGLTF_NOEXCEPT noexcept
76 #endif
77 #else
78 #define TINYGLTF_NOEXCEPT noexcept
79 #endif
80
81 #define DEFAULT_METHODS(x) \
82 ~x() = default; \
83 x(const x &) = default; \
84 x(x &&) TINYGLTF_NOEXCEPT = default; \
85 x &operator=(const x &) = default; \
86 x &operator=(x &&) TINYGLTF_NOEXCEPT = default;
5787
5888 namespace tinygltf {
5989
156186
157187 typedef enum {
158188 NULL_TYPE = 0,
159 NUMBER_TYPE = 1,
189 REAL_TYPE = 1,
160190 INT_TYPE = 2,
161191 BOOL_TYPE = 3,
162192 STRING_TYPE = 4,
188218 }
189219 }
190220
191 static inline int32_t GetTypeSizeInBytes(uint32_t ty) {
221 static inline int32_t GetNumComponentsInType(uint32_t ty) {
192222 if (ty == TINYGLTF_TYPE_SCALAR) {
193223 return 1;
194224 } else if (ty == TINYGLTF_TYPE_VEC2) {
209239 }
210240 }
211241
242 // TODO(syoyo): Move these functions to TinyGLTF class
212243 bool IsDataURI(const std::string &in);
213244 bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
214245 const std::string &in, size_t reqBytes, bool checkSize);
227258 typedef std::vector<Value> Array;
228259 typedef std::map<std::string, Value> Object;
229260
230 Value() : type_(NULL_TYPE) {}
261 Value()
262 : type_(NULL_TYPE),
263 int_value_(0),
264 real_value_(0.0),
265 boolean_value_(false) {}
231266
232267 explicit Value(bool b) : type_(BOOL_TYPE) { boolean_value_ = b; }
233 explicit Value(int i) : type_(INT_TYPE) { int_value_ = i; }
234 explicit Value(double n) : type_(NUMBER_TYPE) { number_value_ = n; }
268 explicit Value(int i) : type_(INT_TYPE) {
269 int_value_ = i;
270 real_value_ = i;
271 }
272 explicit Value(double n) : type_(REAL_TYPE) { real_value_ = n; }
235273 explicit Value(const std::string &s) : type_(STRING_TYPE) {
236274 string_value_ = s;
237275 }
276 explicit Value(std::string &&s)
277 : type_(STRING_TYPE), string_value_(std::move(s)) {}
238278 explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) {
239279 binary_value_.resize(n);
240280 memcpy(binary_value_.data(), p, n);
241281 }
242 explicit Value(const Array &a) : type_(ARRAY_TYPE) {
243 array_value_ = Array(a);
244 }
245 explicit Value(const Object &o) : type_(OBJECT_TYPE) {
246 object_value_ = Object(o);
247 }
282 explicit Value(std::vector<unsigned char> &&v) noexcept
283 : type_(BINARY_TYPE),
284 binary_value_(std::move(v)) {}
285 explicit Value(const Array &a) : type_(ARRAY_TYPE) { array_value_ = a; }
286 explicit Value(Array &&a) noexcept : type_(ARRAY_TYPE),
287 array_value_(std::move(a)) {}
288
289 explicit Value(const Object &o) : type_(OBJECT_TYPE) { object_value_ = o; }
290 explicit Value(Object &&o) noexcept : type_(OBJECT_TYPE),
291 object_value_(std::move(o)) {}
292
293 DEFAULT_METHODS(Value)
248294
249295 char Type() const { return static_cast<const char>(type_); }
250296
252298
253299 bool IsInt() const { return (type_ == INT_TYPE); }
254300
255 bool IsNumber() const { return (type_ == NUMBER_TYPE); }
301 bool IsNumber() const { return (type_ == REAL_TYPE) || (type_ == INT_TYPE); }
302
303 bool IsReal() const { return (type_ == REAL_TYPE); }
256304
257305 bool IsString() const { return (type_ == STRING_TYPE); }
258306
261309 bool IsArray() const { return (type_ == ARRAY_TYPE); }
262310
263311 bool IsObject() const { return (type_ == OBJECT_TYPE); }
312
313 // Use this function if you want to have number value as double.
314 double GetNumberAsDouble() const {
315 if (type_ == INT_TYPE) {
316 return double(int_value_);
317 } else {
318 return real_value_;
319 }
320 }
321
322 // Use this function if you want to have number value as int.
323 double GetNumberAsInt() const {
324 if (type_ == REAL_TYPE) {
325 return int(real_value_);
326 } else {
327 return int_value_;
328 }
329 }
264330
265331 // Accessor
266332 template <typename T>
316382 bool operator==(const tinygltf::Value &other) const;
317383
318384 protected:
319 int type_;
320
321 int int_value_;
322 double number_value_;
385 int type_ = NULL_TYPE;
386
387 int int_value_ = 0;
388 double real_value_ = 0.0;
323389 std::string string_value_;
324390 std::vector<unsigned char> binary_value_;
325391 Array array_value_;
326392 Object object_value_;
327 bool boolean_value_;
393 bool boolean_value_ = false;
328394 };
329395
330396 #ifdef __clang__
341407 return var; \
342408 }
343409 TINYGLTF_VALUE_GET(bool, boolean_value_)
344 TINYGLTF_VALUE_GET(double, number_value_)
410 TINYGLTF_VALUE_GET(double, real_value_)
345411 TINYGLTF_VALUE_GET(int, int_value_)
346412 TINYGLTF_VALUE_GET(std::string, string_value_)
347413 TINYGLTF_VALUE_GET(std::vector<unsigned char>, binary_value_)
358424 /// Agregate object for representing a color
359425 using ColorValue = std::array<double, 4>;
360426
427 // === legacy interface ====
428 // TODO(syoyo): Deprecate `Parameter` class.
361429 struct Parameter {
362430 bool bool_value = false;
363431 bool has_number_value = false;
365433 std::vector<double> number_array;
366434 std::map<std::string, double> json_double_value;
367435 double number_value = 0.0;
436
368437 // context sensitive methods. depending the type of the Parameter you are
369438 // accessing, these are either valid or not
370439 // If this parameter represent a texture map in a material, will return the
389458 if (it != std::end(json_double_value)) {
390459 return int(it->second);
391460 }
461 // As per the spec, if texCoord is ommited, this parameter is 0
392462 return 0;
463 }
464
465 /// Return the scale of a texture if this Parameter is a normal texture map.
466 /// Returned value is only valid if the parameter represent a normal texture
467 /// from a material
468 double TextureScale() const {
469 const auto it = json_double_value.find("scale");
470 if (it != std::end(json_double_value)) {
471 return it->second;
472 }
473 // As per the spec, if scale is ommited, this paramter is 1
474 return 1;
475 }
476
477 /// Return the strength of a texture if this Parameter is a an occlusion map.
478 /// Returned value is only valid if the parameter represent an occlusion map
479 /// from a material
480 double TextureStrength() const {
481 const auto it = json_double_value.find("strength");
482 if (it != std::end(json_double_value)) {
483 return it->second;
484 }
485 // As per the spec, if strenghth is ommited, this parameter is 1
486 return 1;
393487 }
394488
395489 /// Material factor, like the roughness or metalness of a material
407501 (number_array.size() > 3 ? number_array[3] : 1.0)}};
408502 }
409503
504 Parameter() = default;
505 DEFAULT_METHODS(Parameter)
410506 bool operator==(const Parameter &) const;
411507 };
412508
428524 std::string target_path; // required in ["translation", "rotation", "scale",
429525 // "weights"]
430526 Value extras;
527 ExtensionMap extensions;
528 ExtensionMap target_extensions;
529
530 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
531 std::string extras_json_string;
532 std::string extensions_json_string;
533 std::string target_extensions_json_string;
431534
432535 AnimationChannel() : sampler(-1), target_node(-1) {}
536 DEFAULT_METHODS(AnimationChannel)
433537 bool operator==(const AnimationChannel &) const;
434538 };
435539
436540 struct AnimationSampler {
437541 int input; // required
438542 int output; // required
439 std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE",
440 // "CUBICSPLINE"], default "LINEAR"
543 std::string interpolation; // "LINEAR", "STEP","CUBICSPLINE" or user defined
544 // string. default "LINEAR"
441545 Value extras;
546 ExtensionMap extensions;
547
548 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
549 std::string extras_json_string;
550 std::string extensions_json_string;
442551
443552 AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {}
553 DEFAULT_METHODS(AnimationSampler)
444554 bool operator==(const AnimationSampler &) const;
445555 };
446556
449559 std::vector<AnimationChannel> channels;
450560 std::vector<AnimationSampler> samplers;
451561 Value extras;
452
562 ExtensionMap extensions;
563
564 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
565 std::string extras_json_string;
566 std::string extensions_json_string;
567
568 Animation() = default;
569 DEFAULT_METHODS(Animation)
453570 bool operator==(const Animation &) const;
454571 };
455572
459576 int skeleton; // The index of the node used as a skeleton root
460577 std::vector<int> joints; // Indices of skeleton nodes
461578
579 Value extras;
580 ExtensionMap extensions;
581
582 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
583 std::string extras_json_string;
584 std::string extensions_json_string;
585
462586 Skin() {
463587 inverseBindMatrices = -1;
464588 skeleton = -1;
465589 }
590 DEFAULT_METHODS(Skin)
466591 bool operator==(const Skin &) const;
467592 };
468593
469594 struct Sampler {
470595 std::string name;
471 int minFilter; // ["NEAREST", "LINEAR", "NEAREST_MIPMAP_LINEAR",
472 // "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR",
473 // "LINEAR_MIPMAP_LINEAR"]
474 int magFilter; // ["NEAREST", "LINEAR"]
475 int wrapS; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default
476 // "REPEAT"
477 int wrapT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default
478 // "REPEAT"
479 int wrapR; // TinyGLTF extension
596 // glTF 2.0 spec does not define default value for `minFilter` and
597 // `magFilter`. Set -1 in TinyGLTF(issue #186)
598 int minFilter =
599 -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
600 // "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST",
601 // "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
602 int magFilter =
603 -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
604 int wrapS =
605 TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
606 // "REPEAT"], default "REPEAT"
607 int wrapT =
608 TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
609 // "REPEAT"], default "REPEAT"
610 int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension
611
480612 Value extras;
613 ExtensionMap extensions;
614
615 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
616 std::string extras_json_string;
617 std::string extensions_json_string;
481618
482619 Sampler()
483 : minFilter(TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR),
484 magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR),
620 : minFilter(-1),
621 magFilter(-1),
485622 wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
486623 wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
487624 wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
625 DEFAULT_METHODS(Sampler)
488626 bool operator==(const Sampler &) const;
489627 };
490628
504642 Value extras;
505643 ExtensionMap extensions;
506644
645 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
646 std::string extras_json_string;
647 std::string extensions_json_string;
648
507649 // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg
508650 // compressed for "image/jpeg" mime) This feature is good if you use custom
509651 // image loader function. (e.g. delayed decoding of images for faster glTF
518660 height = -1;
519661 component = -1;
520662 }
663 DEFAULT_METHODS(Image)
664
521665 bool operator==(const Image &) const;
522666 };
523667
529673 Value extras;
530674 ExtensionMap extensions;
531675
676 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
677 std::string extras_json_string;
678 std::string extensions_json_string;
679
532680 Texture() : sampler(-1), source(-1) {}
681 DEFAULT_METHODS(Texture)
682
533683 bool operator==(const Texture &) const;
684 };
685
686 struct TextureInfo {
687 int index = -1; // required.
688 int texCoord; // The set index of texture's TEXCOORD attribute used for
689 // texture coordinate mapping.
690
691 Value extras;
692 ExtensionMap extensions;
693
694 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
695 std::string extras_json_string;
696 std::string extensions_json_string;
697
698 TextureInfo() : index(-1), texCoord(0) {}
699 DEFAULT_METHODS(TextureInfo)
700 bool operator==(const TextureInfo &) const;
701 };
702
703 struct NormalTextureInfo {
704 int index = -1; // required
705 int texCoord; // The set index of texture's TEXCOORD attribute used for
706 // texture coordinate mapping.
707 double scale; // scaledNormal = normalize((<sampled normal texture value>
708 // * 2.0 - 1.0) * vec3(<normal scale>, <normal scale>, 1.0))
709
710 Value extras;
711 ExtensionMap extensions;
712
713 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
714 std::string extras_json_string;
715 std::string extensions_json_string;
716
717 NormalTextureInfo() : index(-1), texCoord(0), scale(1.0) {}
718 DEFAULT_METHODS(NormalTextureInfo)
719 bool operator==(const NormalTextureInfo &) const;
720 };
721
722 struct OcclusionTextureInfo {
723 int index = -1; // required
724 int texCoord; // The set index of texture's TEXCOORD attribute used for
725 // texture coordinate mapping.
726 double strength; // occludedColor = lerp(color, color * <sampled occlusion
727 // texture value>, <occlusion strength>)
728
729 Value extras;
730 ExtensionMap extensions;
731
732 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
733 std::string extras_json_string;
734 std::string extensions_json_string;
735
736 OcclusionTextureInfo() : index(-1), texCoord(0), strength(1.0) {}
737 DEFAULT_METHODS(OcclusionTextureInfo)
738 bool operator==(const OcclusionTextureInfo &) const;
739 };
740
741 // pbrMetallicRoughness class defined in glTF 2.0 spec.
742 struct PbrMetallicRoughness {
743 std::vector<double> baseColorFactor; // len = 4. default [1,1,1,1]
744 TextureInfo baseColorTexture;
745 double metallicFactor; // default 1
746 double roughnessFactor; // default 1
747 TextureInfo metallicRoughnessTexture;
748
749 Value extras;
750 ExtensionMap extensions;
751
752 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
753 std::string extras_json_string;
754 std::string extensions_json_string;
755
756 PbrMetallicRoughness()
757 : baseColorFactor(std::vector<double>{1.0, 1.0, 1.0, 1.0}),
758 metallicFactor(1.0),
759 roughnessFactor(1.0) {}
760 DEFAULT_METHODS(PbrMetallicRoughness)
761 bool operator==(const PbrMetallicRoughness &) const;
534762 };
535763
536764 // Each extension should be stored in a ParameterMap.
539767 struct Material {
540768 std::string name;
541769
542 ParameterMap values; // PBR metal/roughness workflow
543 ParameterMap additionalValues; // normal/occlusion/emissive values
770 std::vector<double> emissiveFactor; // length 3. default [0, 0, 0]
771 std::string alphaMode; // default "OPAQUE"
772 double alphaCutoff; // default 0.5
773 bool doubleSided; // default false;
774
775 PbrMetallicRoughness pbrMetallicRoughness;
776
777 NormalTextureInfo normalTexture;
778 OcclusionTextureInfo occlusionTexture;
779 TextureInfo emissiveTexture;
780
781 // For backward compatibility
782 // TODO(syoyo): Remove `values` and `additionalValues` in the next release.
783 ParameterMap values;
784 ParameterMap additionalValues;
544785
545786 ExtensionMap extensions;
546787 Value extras;
547788
789 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
790 std::string extras_json_string;
791 std::string extensions_json_string;
792
793 Material() : alphaMode("OPAQUE"), alphaCutoff(0.5), doubleSided(false) {}
794 DEFAULT_METHODS(Material)
795
548796 bool operator==(const Material &) const;
549797 };
550798
551799 struct BufferView {
552800 std::string name;
553 int buffer; // Required
554 size_t byteOffset; // minimum 0, default 0
555 size_t byteLength; // required, minimum 1
556 size_t byteStride; // minimum 4, maximum 252 (multiple of 4), default 0 =
801 int buffer{-1}; // Required
802 size_t byteOffset{0}; // minimum 0, default 0
803 size_t byteLength{0}; // required, minimum 1. 0 = invalid
804 size_t byteStride{0}; // minimum 4, maximum 252 (multiple of 4), default 0 =
557805 // understood to be tightly packed
558 int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"]
806 int target{0}; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices or atttribs. Could be 0 for other data
559807 Value extras;
560 bool dracoDecoded; // Flag indicating this has been draco decoded
561
562 BufferView() : byteOffset(0), byteStride(0), dracoDecoded(false) {}
808 ExtensionMap extensions;
809
810 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
811 std::string extras_json_string;
812 std::string extensions_json_string;
813
814 bool dracoDecoded{false}; // Flag indicating this has been draco decoded
815
816 BufferView() : buffer(-1), byteOffset(0), byteLength(0), byteStride(0), target(0), dracoDecoded(false) {}
817 DEFAULT_METHODS(BufferView)
563818 bool operator==(const BufferView &) const;
564819 };
565820
573828 size_t count; // required
574829 int type; // (required) One of TINYGLTF_TYPE_*** ..
575830 Value extras;
831 ExtensionMap extensions;
832
833 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
834 std::string extras_json_string;
835 std::string extensions_json_string;
576836
577837 std::vector<double> minValues; // optional
578838 std::vector<double> maxValues; // optional
604864 return -1;
605865 }
606866
607 int typeSizeInBytes = GetTypeSizeInBytes(static_cast<uint32_t>(type));
608 if (typeSizeInBytes <= 0) {
867 int numComponents = GetNumComponentsInType(static_cast<uint32_t>(type));
868 if (numComponents <= 0) {
609869 return -1;
610870 }
611871
612 return componentSizeInBytes * typeSizeInBytes;
872 return componentSizeInBytes * numComponents;
613873 } else {
614874 // Check if byteStride is a mulple of the size of the accessor's component
615875 // type.
625885 return static_cast<int>(bufferViewObject.byteStride);
626886 }
627887
628 return 0;
629 }
630
631 Accessor() {
632 bufferView = -1;
888 // unreachable return 0;
889 }
890
891 Accessor() :
892 bufferView(-1),
893 byteOffset(0),
894 normalized(false),
895 componentType(-1),
896 count(0),
897 type(-1){
633898 sparse.isSparse = false;
634899 }
900 DEFAULT_METHODS(Accessor)
635901 bool operator==(const tinygltf::Accessor &) const;
636902 };
637903
647913 zfar(0.0) // 0 = use infinite projecton matrix
648914 ,
649915 znear(0.0) {}
916 DEFAULT_METHODS(PerspectiveCamera)
650917 bool operator==(const PerspectiveCamera &) const;
651918
652919 ExtensionMap extensions;
653920 Value extras;
921
922 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
923 std::string extras_json_string;
924 std::string extensions_json_string;
654925 };
655926
656927 struct OrthographicCamera {
660931 double znear; // required
661932
662933 OrthographicCamera() : xmag(0.0), ymag(0.0), zfar(0.0), znear(0.0) {}
934 DEFAULT_METHODS(OrthographicCamera)
663935 bool operator==(const OrthographicCamera &) const;
664936
665937 ExtensionMap extensions;
666938 Value extras;
939
940 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
941 std::string extras_json_string;
942 std::string extensions_json_string;
667943 };
668944
669945 struct Camera {
674950 OrthographicCamera orthographic;
675951
676952 Camera() {}
953 DEFAULT_METHODS(Camera)
677954 bool operator==(const Camera &) const;
678955
679956 ExtensionMap extensions;
680957 Value extras;
958
959 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
960 std::string extras_json_string;
961 std::string extensions_json_string;
681962 };
682963
683964 struct Primitive {
696977 ExtensionMap extensions;
697978 Value extras;
698979
980 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
981 std::string extras_json_string;
982 std::string extensions_json_string;
983
699984 Primitive() {
700985 material = -1;
701986 indices = -1;
702987 }
988 DEFAULT_METHODS(Primitive)
703989 bool operator==(const Primitive &) const;
704990 };
705991
707993 std::string name;
708994 std::vector<Primitive> primitives;
709995 std::vector<double> weights; // weights to be applied to the Morph Targets
710 std::vector<std::map<std::string, int> > targets;
711996 ExtensionMap extensions;
712997 Value extras;
713998
999 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1000 std::string extras_json_string;
1001 std::string extensions_json_string;
1002
1003 Mesh() = default;
1004 DEFAULT_METHODS(Mesh)
7141005 bool operator==(const Mesh &) const;
7151006 };
7161007
7181009 public:
7191010 Node() : camera(-1), skin(-1), mesh(-1) {}
7201011
721 Node(const Node &rhs) {
722 camera = rhs.camera;
723
724 name = rhs.name;
725 skin = rhs.skin;
726 mesh = rhs.mesh;
727 children = rhs.children;
728 rotation = rhs.rotation;
729 scale = rhs.scale;
730 translation = rhs.translation;
731 matrix = rhs.matrix;
732 weights = rhs.weights;
733
734 extensions = rhs.extensions;
735 extras = rhs.extras;
736 }
737 ~Node() {}
1012 DEFAULT_METHODS(Node)
1013
7381014 bool operator==(const Node &) const;
7391015
7401016 int camera; // the index of the camera referenced by this node
7511027
7521028 ExtensionMap extensions;
7531029 Value extras;
1030
1031 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1032 std::string extras_json_string;
1033 std::string extensions_json_string;
7541034 };
7551035
7561036 struct Buffer {
7591039 std::string
7601040 uri; // considered as required here but not in the spec (need to clarify)
7611041 Value extras;
762
1042 ExtensionMap extensions;
1043
1044 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1045 std::string extras_json_string;
1046 std::string extensions_json_string;
1047
1048 Buffer() = default;
1049 DEFAULT_METHODS(Buffer)
7631050 bool operator==(const Buffer &) const;
7641051 };
7651052
7711058 ExtensionMap extensions;
7721059 Value extras;
7731060
1061 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1062 std::string extras_json_string;
1063 std::string extensions_json_string;
1064
1065 Asset() = default;
1066 DEFAULT_METHODS(Asset)
7741067 bool operator==(const Asset &) const;
7751068 };
7761069
7811074 ExtensionMap extensions;
7821075 Value extras;
7831076
1077 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1078 std::string extras_json_string;
1079 std::string extensions_json_string;
1080
1081 Scene() = default;
1082 DEFAULT_METHODS(Scene)
7841083 bool operator==(const Scene &) const;
1084 };
1085
1086 struct SpotLight {
1087 double innerConeAngle;
1088 double outerConeAngle;
1089
1090 SpotLight() : innerConeAngle(0.0), outerConeAngle(0.7853981634) {}
1091 DEFAULT_METHODS(SpotLight)
1092 bool operator==(const SpotLight &) const;
1093
1094 ExtensionMap extensions;
1095 Value extras;
1096
1097 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1098 std::string extras_json_string;
1099 std::string extensions_json_string;
7851100 };
7861101
7871102 struct Light {
7881103 std::string name;
7891104 std::vector<double> color;
1105 double intensity;
7901106 std::string type;
1107 double range;
1108 SpotLight spot;
1109
1110 Light() : intensity(1.0), range(0.0) {}
1111 DEFAULT_METHODS(Light)
7911112
7921113 bool operator==(const Light &) const;
1114
1115 ExtensionMap extensions;
1116 Value extras;
1117
1118 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1119 std::string extras_json_string;
1120 std::string extensions_json_string;
7931121 };
7941122
7951123 class Model {
7961124 public:
797 Model() {}
798 ~Model() {}
1125 Model() = default;
1126 DEFAULT_METHODS(Model)
1127
7991128 bool operator==(const Model &) const;
8001129
8011130 std::vector<Accessor> accessors;
8121141 std::vector<Camera> cameras;
8131142 std::vector<Scene> scenes;
8141143 std::vector<Light> lights;
815 ExtensionMap extensions;
816
817 int defaultScene;
1144
1145 int defaultScene = -1;
8181146 std::vector<std::string> extensionsUsed;
8191147 std::vector<std::string> extensionsRequired;
8201148
8211149 Asset asset;
8221150
8231151 Value extras;
1152 ExtensionMap extensions;
1153
1154 // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1155 std::string extras_json_string;
1156 std::string extensions_json_string;
8241157 };
8251158
8261159 enum SectionCheck {
8271160 NO_REQUIRE = 0x00,
828 REQUIRE_SCENE = 0x01,
829 REQUIRE_SCENES = 0x02,
830 REQUIRE_NODES = 0x04,
831 REQUIRE_ACCESSORS = 0x08,
832 REQUIRE_BUFFERS = 0x10,
833 REQUIRE_BUFFER_VIEWS = 0x20,
834 REQUIRE_ALL = 0x3f
1161 REQUIRE_VERSION = 0x01,
1162 REQUIRE_SCENE = 0x02,
1163 REQUIRE_SCENES = 0x04,
1164 REQUIRE_NODES = 0x08,
1165 REQUIRE_ACCESSORS = 0x10,
1166 REQUIRE_BUFFERS = 0x20,
1167 REQUIRE_BUFFER_VIEWS = 0x40,
1168 REQUIRE_ALL = 0x7f
8351169 };
8361170
8371171 ///
9111245 const std::vector<unsigned char> &contents, void *);
9121246 #endif
9131247
1248 ///
1249 /// glTF Parser/Serialier context.
1250 ///
9141251 class TinyGLTF {
9151252 public:
9161253 #ifdef __clang__
9331270 ///
9341271 bool LoadASCIIFromFile(Model *model, std::string *err, std::string *warn,
9351272 const std::string &filename,
936 unsigned int check_sections = REQUIRE_ALL);
1273 unsigned int check_sections = REQUIRE_VERSION);
9371274
9381275 ///
9391276 /// Loads glTF ASCII asset from string(memory).
9441281 bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn,
9451282 const char *str, const unsigned int length,
9461283 const std::string &base_dir,
947 unsigned int check_sections = REQUIRE_ALL);
1284 unsigned int check_sections = REQUIRE_VERSION);
9481285
9491286 ///
9501287 /// Loads glTF binary asset from a file.
9531290 ///
9541291 bool LoadBinaryFromFile(Model *model, std::string *err, std::string *warn,
9551292 const std::string &filename,
956 unsigned int check_sections = REQUIRE_ALL);
1293 unsigned int check_sections = REQUIRE_VERSION);
9571294
9581295 ///
9591296 /// Loads glTF binary asset from memory.
9651302 const unsigned char *bytes,
9661303 const unsigned int length,
9671304 const std::string &base_dir = "",
968 unsigned int check_sections = REQUIRE_ALL);
1305 unsigned int check_sections = REQUIRE_VERSION);
1306
1307 ///
1308 /// Write glTF to stream, buffers and images will be embeded
1309 ///
1310 bool WriteGltfSceneToStream(Model *model, std::ostream &stream,
1311 bool prettyPrint, bool writeBinary);
9691312
9701313 ///
9711314 /// Write glTF to file.
9881331 /// Set callbacks to use for filesystem (fs) access and their user data
9891332 ///
9901333 void SetFsCallbacks(FsCallbacks callbacks);
1334
1335 ///
1336 /// Set serializing default values(default = false).
1337 /// When true, default values are force serialized to .glTF.
1338 /// This may be helpfull if you want to serialize a full description of glTF
1339 /// data.
1340 ///
1341 /// TODO(LTE): Supply parsing option as function arguments to
1342 /// `LoadASCIIFromFile()` and others, not by a class method
1343 ///
1344 void SetSerializeDefaultValues(const bool enabled) {
1345 serialize_default_values_ = enabled;
1346 }
1347
1348 bool GetSerializeDefaultValues() const { return serialize_default_values_; }
1349
1350 ///
1351 /// Store original JSON string for `extras` and `extensions`.
1352 /// This feature will be useful when the user want to reconstruct custom data
1353 /// structure from JSON string.
1354 ///
1355 void SetStoreOriginalJSONForExtrasAndExtensions(const bool enabled) {
1356 store_original_json_for_extras_and_extensions_ = enabled;
1357 }
1358
1359 bool GetStoreOriginalJSONForExtrasAndExtensions() const {
1360 return store_original_json_for_extras_and_extensions_;
1361 }
9911362
9921363 private:
9931364 ///
10001371 const char *str, const unsigned int length,
10011372 const std::string &base_dir, unsigned int check_sections);
10021373
1003 const unsigned char *bin_data_;
1004 size_t bin_size_;
1005 bool is_binary_;
1374 const unsigned char *bin_data_ = nullptr;
1375 size_t bin_size_ = 0;
1376 bool is_binary_ = false;
1377
1378 bool serialize_default_values_ = false; ///< Serialize default values?
1379
1380 bool store_original_json_for_extras_and_extensions_ = false;
10061381
10071382 FsCallbacks fs = {
10081383 #ifndef TINYGLTF_NO_FS
10461421 #include <algorithm>
10471422 //#include <cassert>
10481423 #ifndef TINYGLTF_NO_FS
1424 #include <cstdio>
10491425 #include <fstream>
10501426 #endif
10511427 #include <sstream>
10581434 #pragma clang diagnostic ignored "-Wconversion"
10591435 #pragma clang diagnostic ignored "-Wold-style-cast"
10601436 #pragma clang diagnostic ignored "-Wglobal-constructors"
1437 #if __has_warning("-Wreserved-id-macro")
10611438 #pragma clang diagnostic ignored "-Wreserved-id-macro"
1439 #endif
10621440 #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
10631441 #pragma clang diagnostic ignored "-Wpadded"
10641442 #pragma clang diagnostic ignored "-Wc++98-compat"
10981476 #if __has_warning("-Wmismatched-tags")
10991477 #pragma clang diagnostic ignored "-Wmismatched-tags"
11001478 #endif
1479 #if __has_warning("-Wextra-semi-stmt")
1480 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
1481 #endif
11011482 #endif
11021483
11031484 // Disable GCC warnigs
11071488 #endif // __GNUC__
11081489
11091490 #ifndef TINYGLTF_NO_INCLUDE_JSON
1491 #ifndef TINYGLTF_USE_RAPIDJSON
11101492 #include "json.hpp"
1493 #else
1494 #include "document.h"
1495 #include "prettywriter.h"
1496 #include "rapidjson.h"
1497 #include "stringbuffer.h"
1498 #include "writer.h"
1499 #endif
11111500 #endif
11121501
11131502 #ifdef TINYGLTF_ENABLE_DRACO
11591548 #undef NOMINMAX
11601549 #endif
11611550
1551 #if defined(__GLIBCXX__) // mingw
1552
1553 #include <ext/stdio_filebuf.h> // fstream (all sorts of IO stuff) + stdio_filebuf (=streambuf)
1554 #include <fcntl.h> // _O_RDONLY
1555
1556 #endif
1557
11621558 #elif !defined(__ANDROID__)
11631559 #include <wordexp.h>
11641560 #endif
11711567 #endif
11721568 #endif
11731569
1570 namespace {
1571 #ifdef TINYGLTF_USE_RAPIDJSON
1572
1573 #ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1574 // This uses the RapidJSON CRTAllocator. It is thread safe and multiple
1575 // documents may be active at once.
1576 using json =
1577 rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
1578 using json_const_iterator = json::ConstMemberIterator;
1579 using json_const_array_iterator = json const *;
1580 using JsonDocument =
1581 rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
1582 rapidjson::CrtAllocator s_CrtAllocator; // stateless and thread safe
1583 rapidjson::CrtAllocator &GetAllocator() { return s_CrtAllocator; }
1584 #else
1585 // This uses the default RapidJSON MemoryPoolAllocator. It is very fast, but
1586 // not thread safe. Only a single JsonDocument may be active at any one time,
1587 // meaning only a single gltf load/save can be active any one time.
1588 using json = rapidjson::Value;
1589 using json_const_iterator = json::ConstMemberIterator;
1590 using json_const_array_iterator = json const *;
1591 rapidjson::Document *s_pActiveDocument = nullptr;
1592 rapidjson::Document::AllocatorType &GetAllocator() {
1593 assert(s_pActiveDocument); // Root json node must be JsonDocument type
1594 return s_pActiveDocument->GetAllocator();
1595 }
1596
1597 #ifdef __clang__
1598 #pragma clang diagnostic push
1599 // Suppress JsonDocument(JsonDocument &&rhs) noexcept
1600 #pragma clang diagnostic ignored "-Wunused-member-function"
1601 #endif
1602
1603 struct JsonDocument : public rapidjson::Document {
1604 JsonDocument() {
1605 assert(s_pActiveDocument ==
1606 nullptr); // When using default allocator, only one document can be
1607 // active at a time, if you need multiple active at once,
1608 // define TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1609 s_pActiveDocument = this;
1610 }
1611 JsonDocument(const JsonDocument &) = delete;
1612 JsonDocument(JsonDocument &&rhs) noexcept
1613 : rapidjson::Document(std::move(rhs)) {
1614 s_pActiveDocument = this;
1615 rhs.isNil = true;
1616 }
1617 ~JsonDocument() {
1618 if (!isNil) {
1619 s_pActiveDocument = nullptr;
1620 }
1621 }
1622
1623 private:
1624 bool isNil = false;
1625 };
1626
1627 #ifdef __clang__
1628 #pragma clang diagnostic pop
1629 #endif
1630
1631 #endif // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1632
1633 #else
11741634 using nlohmann::json;
1635 using json_const_iterator = json::const_iterator;
1636 using json_const_array_iterator = json_const_iterator;
1637 using JsonDocument = json;
1638 #endif
1639
1640 void JsonParse(JsonDocument &doc, const char *str, size_t length,
1641 bool throwExc = false) {
1642 #ifdef TINYGLTF_USE_RAPIDJSON
1643 (void)throwExc;
1644 doc.Parse(str, length);
1645 #else
1646 doc = json::parse(str, str + length, nullptr, throwExc);
1647 #endif
1648 }
1649 } // namespace
11751650
11761651 #ifdef __APPLE__
11771652 #include "TargetConditionals.h"
11931668 return true;
11941669 case BOOL_TYPE:
11951670 return one.Get<bool>() == other.Get<bool>();
1196 case NUMBER_TYPE:
1671 case REAL_TYPE:
11971672 return TINYGLTF_DOUBLE_EQUAL(one.Get<double>(), other.Get<double>());
11981673 case INT_TYPE:
11991674 return one.Get<int>() == other.Get<int>();
12411716 return this->bufferView == other.bufferView &&
12421717 this->byteOffset == other.byteOffset &&
12431718 this->componentType == other.componentType &&
1244 this->count == other.count && this->extras == other.extras &&
1719 this->count == other.count && this->extensions == other.extensions &&
1720 this->extras == other.extras &&
12451721 Equals(this->maxValues, other.maxValues) &&
12461722 Equals(this->minValues, other.minValues) && this->name == other.name &&
12471723 this->normalized == other.normalized && this->type == other.type;
12481724 }
12491725 bool Animation::operator==(const Animation &other) const {
1250 return this->channels == other.channels && this->extras == other.extras &&
1726 return this->channels == other.channels &&
1727 this->extensions == other.extensions && this->extras == other.extras &&
12511728 this->name == other.name && this->samplers == other.samplers;
12521729 }
12531730 bool AnimationChannel::operator==(const AnimationChannel &other) const {
1254 return this->extras == other.extras &&
1731 return this->extensions == other.extensions && this->extras == other.extras &&
12551732 this->target_node == other.target_node &&
12561733 this->target_path == other.target_path &&
12571734 this->sampler == other.sampler;
12581735 }
12591736 bool AnimationSampler::operator==(const AnimationSampler &other) const {
1260 return this->extras == other.extras && this->input == other.input &&
1737 return this->extras == other.extras && this->extensions == other.extensions &&
1738 this->input == other.input &&
12611739 this->interpolation == other.interpolation &&
12621740 this->output == other.output;
12631741 }
12681746 this->minVersion == other.minVersion && this->version == other.version;
12691747 }
12701748 bool Buffer::operator==(const Buffer &other) const {
1271 return this->data == other.data && this->extras == other.extras &&
1272 this->name == other.name && this->uri == other.uri;
1749 return this->data == other.data && this->extensions == other.extensions &&
1750 this->extras == other.extras && this->name == other.name &&
1751 this->uri == other.uri;
12731752 }
12741753 bool BufferView::operator==(const BufferView &other) const {
12751754 return this->buffer == other.buffer && this->byteLength == other.byteLength &&
12761755 this->byteOffset == other.byteOffset &&
12771756 this->byteStride == other.byteStride && this->name == other.name &&
1278 this->target == other.target && this->extras == other.extras &&
1757 this->target == other.target && this->extensions == other.extensions &&
1758 this->extras == other.extras &&
12791759 this->dracoDecoded == other.dracoDecoded;
12801760 }
12811761 bool Camera::operator==(const Camera &other) const {
12861766 }
12871767 bool Image::operator==(const Image &other) const {
12881768 return this->bufferView == other.bufferView &&
1289 this->component == other.component && this->extras == other.extras &&
1769 this->component == other.component &&
1770 this->extensions == other.extensions && this->extras == other.extras &&
12901771 this->height == other.height && this->image == other.image &&
12911772 this->mimeType == other.mimeType && this->name == other.name &&
12921773 this->uri == other.uri && this->width == other.width;
12961777 this->type == other.type;
12971778 }
12981779 bool Material::operator==(const Material &other) const {
1299 return this->additionalValues == other.additionalValues &&
1300 this->extensions == other.extensions && this->extras == other.extras &&
1301 this->name == other.name && this->values == other.values;
1780 return (this->pbrMetallicRoughness == other.pbrMetallicRoughness) &&
1781 (this->normalTexture == other.normalTexture) &&
1782 (this->occlusionTexture == other.occlusionTexture) &&
1783 (this->emissiveTexture == other.emissiveTexture) &&
1784 Equals(this->emissiveFactor, other.emissiveFactor) &&
1785 (this->alphaMode == other.alphaMode) &&
1786 TINYGLTF_DOUBLE_EQUAL(this->alphaCutoff, other.alphaCutoff) &&
1787 (this->doubleSided == other.doubleSided) &&
1788 (this->extensions == other.extensions) &&
1789 (this->extras == other.extras) && (this->values == other.values) &&
1790 (this->additionalValues == other.additionalValues) &&
1791 (this->name == other.name);
13021792 }
13031793 bool Mesh::operator==(const Mesh &other) const {
13041794 return this->extensions == other.extensions && this->extras == other.extras &&
1305 this->name == other.name && this->primitives == other.primitives &&
1306 this->targets == other.targets && Equals(this->weights, other.weights);
1795 this->name == other.name && Equals(this->weights, other.weights) &&
1796 this->primitives == other.primitives;
13071797 }
13081798 bool Model::operator==(const Model &other) const {
13091799 return this->accessors == other.accessors &&
13301820 Equals(this->translation, other.translation) &&
13311821 Equals(this->weights, other.weights);
13321822 }
1823 bool SpotLight::operator==(const SpotLight &other) const {
1824 return this->extensions == other.extensions && this->extras == other.extras &&
1825 TINYGLTF_DOUBLE_EQUAL(this->innerConeAngle, other.innerConeAngle) &&
1826 TINYGLTF_DOUBLE_EQUAL(this->outerConeAngle, other.outerConeAngle);
1827 }
13331828 bool OrthographicCamera::operator==(const OrthographicCamera &other) const {
13341829 return this->extensions == other.extensions && this->extras == other.extras &&
13351830 TINYGLTF_DOUBLE_EQUAL(this->xmag, other.xmag) &&
13731868 this->mode == other.mode && this->targets == other.targets;
13741869 }
13751870 bool Sampler::operator==(const Sampler &other) const {
1376 return this->extras == other.extras && this->magFilter == other.magFilter &&
1871 return this->extensions == other.extensions && this->extras == other.extras &&
1872 this->magFilter == other.magFilter &&
13771873 this->minFilter == other.minFilter && this->name == other.name &&
13781874 this->wrapR == other.wrapR && this->wrapS == other.wrapS &&
13791875 this->wrapT == other.wrapT;
13811877 bool Scene::operator==(const Scene &other) const {
13821878 return this->extensions == other.extensions && this->extras == other.extras &&
13831879 this->name == other.name && this->nodes == other.nodes;
1384 ;
13851880 }
13861881 bool Skin::operator==(const Skin &other) const {
1387 return this->inverseBindMatrices == other.inverseBindMatrices &&
1882 return this->extensions == other.extensions && this->extras == other.extras &&
1883 this->inverseBindMatrices == other.inverseBindMatrices &&
13881884 this->joints == other.joints && this->name == other.name &&
13891885 this->skeleton == other.skeleton;
13901886 }
13921888 return this->extensions == other.extensions && this->extras == other.extras &&
13931889 this->name == other.name && this->sampler == other.sampler &&
13941890 this->source == other.source;
1891 }
1892 bool TextureInfo::operator==(const TextureInfo &other) const {
1893 return this->extensions == other.extensions && this->extras == other.extras &&
1894 this->index == other.index && this->texCoord == other.texCoord;
1895 }
1896 bool NormalTextureInfo::operator==(const NormalTextureInfo &other) const {
1897 return this->extensions == other.extensions && this->extras == other.extras &&
1898 this->index == other.index && this->texCoord == other.texCoord &&
1899 TINYGLTF_DOUBLE_EQUAL(this->scale, other.scale);
1900 }
1901 bool OcclusionTextureInfo::operator==(const OcclusionTextureInfo &other) const {
1902 return this->extensions == other.extensions && this->extras == other.extras &&
1903 this->index == other.index && this->texCoord == other.texCoord &&
1904 TINYGLTF_DOUBLE_EQUAL(this->strength, other.strength);
1905 }
1906 bool PbrMetallicRoughness::operator==(const PbrMetallicRoughness &other) const {
1907 return this->extensions == other.extensions && this->extras == other.extras &&
1908 (this->baseColorTexture == other.baseColorTexture) &&
1909 (this->metallicRoughnessTexture == other.metallicRoughnessTexture) &&
1910 Equals(this->baseColorFactor, other.baseColorFactor) &&
1911 TINYGLTF_DOUBLE_EQUAL(this->metallicFactor, other.metallicFactor) &&
1912 TINYGLTF_DOUBLE_EQUAL(this->roughnessFactor, other.roughnessFactor);
13951913 }
13961914 bool Value::operator==(const Value &other) const {
13971915 return Equals(*this, other);
14952013
14962014 #ifdef __clang__
14972015 #pragma clang diagnostic push
1498 #pragma clang diagnostic ignored "-Wexit-time-destructors"
1499 #pragma clang diagnostic ignored "-Wglobal-constructors"
15002016 #pragma clang diagnostic ignored "-Wsign-conversion"
15012017 #pragma clang diagnostic ignored "-Wconversion"
15022018 #endif
1503 static const std::string base64_chars =
1504 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1505 "abcdefghijklmnopqrstuvwxyz"
1506 "0123456789+/";
15072019
15082020 static inline bool is_base64(unsigned char c) {
15092021 return (isalnum(c) || (c == '+') || (c == '/'));
15162028 int j = 0;
15172029 unsigned char char_array_3[3];
15182030 unsigned char char_array_4[4];
2031
2032 const char *base64_chars =
2033 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2034 "abcdefghijklmnopqrstuvwxyz"
2035 "0123456789+/";
15192036
15202037 while (in_len--) {
15212038 char_array_3[i++] = *(bytes_to_encode++);
15562073 int in_ = 0;
15572074 unsigned char char_array_4[4], char_array_3[3];
15582075 std::string ret;
2076
2077 const std::string base64_chars =
2078 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2079 "abcdefghijklmnopqrstuvwxyz"
2080 "0123456789+/";
15592081
15602082 while (in_len-- && (encoded_string[in_] != '=') &&
15612083 is_base64(encoded_string[in_])) {
16782200 (void)user_data;
16792201 (void)warn;
16802202
1681 int w, h, comp, req_comp;
2203 int w = 0, h = 0, comp = 0, req_comp = 0;
16822204
16832205 unsigned char *data = nullptr;
16842206
16952217 // the Image metadata to signal that this image uses 2 bytes (16bits) per
16962218 // channel:
16972219 if (stbi_is_16_bit_from_memory(bytes, size)) {
1698 data = (unsigned char *)stbi_load_16_from_memory(bytes, size, &w, &h, &comp,
1699 req_comp);
2220 data = reinterpret_cast<unsigned char *>(
2221 stbi_load_16_from_memory(bytes, size, &w, &h, &comp, req_comp));
17002222 if (data) {
17012223 bits = 16;
17022224 pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
17232245 return false;
17242246 }
17252247
1726 if (w < 1 || h < 1) {
2248 if ((w < 1) || (h < 1)) {
17272249 stbi_image_free(data);
17282250 if (err) {
17292251 (*err) += "Invalid image data for image[" + std::to_string(image_idx) +
17612283 image->component = req_comp;
17622284 image->bits = bits;
17632285 image->pixel_type = pixel_type;
1764 image->image.resize(static_cast<size_t>(w * h * req_comp) * (bits / 8));
2286 image->image.resize(static_cast<size_t>(w * h * req_comp) * size_t(bits / 8));
17652287 std::copy(data, data + w * h * req_comp * (bits / 8), image->image.begin());
17662288 stbi_image_free(data);
17672289
18562378
18572379 void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
18582380
2381 #ifdef _WIN32
2382 static inline std::wstring UTF8ToWchar(const std::string &str) {
2383 int wstr_size = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
2384 std::wstring wstr(wstr_size, 0);
2385 MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0], (int)wstr.size());
2386 return wstr;
2387 }
2388 #endif
2389
18592390 #ifndef TINYGLTF_NO_FS
18602391 // Default implementations of filesystem functions
18612392
18752406 }
18762407 #else
18772408 #ifdef _WIN32
1878 FILE *fp;
2409 #if defined(_MSC_VER) || defined(__GLIBCXX__)
2410 FILE *fp = nullptr;
2411 errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb");
2412 if (err != 0) {
2413 return false;
2414 }
2415 #else
2416 FILE *fp = nullptr;
18792417 errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
18802418 if (err != 0) {
18812419 return false;
18822420 }
2421 #endif
2422
18832423 #else
18842424 FILE *fp = fopen(abs_filename.c_str(), "rb");
18852425 #endif
19192459 return "";
19202460 }
19212461
2462 // Quote the string to keep any spaces in filepath intact.
2463 std::string quoted_path = "\"" + filepath + "\"";
19222464 // char** w;
1923 int ret = wordexp(filepath.c_str(), &p, 0);
2465 int ret = wordexp(quoted_path.c_str(), &p, 0);
19242466 if (ret) {
19252467 // err
19262468 s = filepath;
19712513 return false;
19722514 }
19732515 #else
2516 #ifdef _WIN32
2517 #if defined(__GLIBCXX__) // mingw
2518 int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
2519 __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
2520 std::istream f(&wfile_buf);
2521 #elif defined(_MSC_VER)
2522 std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
2523 #else // clang?
19742524 std::ifstream f(filepath.c_str(), std::ifstream::binary);
2525 #endif
2526 #else
2527 std::ifstream f(filepath.c_str(), std::ifstream::binary);
2528 #endif
19752529 if (!f) {
19762530 if (err) {
19772531 (*err) += "File open error : " + filepath + "\n";
19832537 size_t sz = static_cast<size_t>(f.tellg());
19842538 f.seekg(0, f.beg);
19852539
1986 if (int(sz) < 0) {
2540 if (int64_t(sz) < 0) {
19872541 if (err) {
19882542 (*err) += "Invalid file size : " + filepath +
19892543 " (does the path point to a directory?)";
19992553 out->resize(sz);
20002554 f.read(reinterpret_cast<char *>(&out->at(0)),
20012555 static_cast<std::streamsize>(sz));
2002 f.close();
20032556
20042557 return true;
20052558 #endif
20072560
20082561 bool WriteWholeFile(std::string *err, const std::string &filepath,
20092562 const std::vector<unsigned char> &contents, void *) {
2563 #ifdef _WIN32
2564 #if defined(__GLIBCXX__) // mingw
2565 int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(), _O_WRONLY | _O_BINARY);
2566 __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
2567 std::ostream f(&wfile_buf);
2568 #elif defined(_MSC_VER)
2569 std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
2570 #else // clang?
20102571 std::ofstream f(filepath.c_str(), std::ofstream::binary);
2572 #endif
2573 #else
2574 std::ofstream f(filepath.c_str(), std::ofstream::binary);
2575 #endif
20112576 if (!f) {
20122577 if (err) {
20132578 (*err) += "File open error for writing : " + filepath + "\n";
20242589 return false;
20252590 }
20262591
2027 f.close();
20282592 return true;
20292593 }
20302594
21672731 }
21682732 }
21692733
2734 // TODO(syoyo): Allow empty buffer? #229
21702735 if (data.empty()) {
21712736 return false;
21722737 }
21832748 return true;
21842749 }
21852750
2751 namespace {
2752 bool GetInt(const json &o, int &val) {
2753 #ifdef TINYGLTF_USE_RAPIDJSON
2754 if (!o.IsDouble()) {
2755 if (o.IsInt()) {
2756 val = o.GetInt();
2757 return true;
2758 } else if (o.IsUint()) {
2759 val = static_cast<int>(o.GetUint());
2760 return true;
2761 } else if (o.IsInt64()) {
2762 val = static_cast<int>(o.GetInt64());
2763 return true;
2764 } else if (o.IsUint64()) {
2765 val = static_cast<int>(o.GetUint64());
2766 return true;
2767 }
2768 }
2769
2770 return false;
2771 #else
2772 auto type = o.type();
2773
2774 if ((type == json::value_t::number_integer) ||
2775 (type == json::value_t::number_unsigned)) {
2776 val = static_cast<int>(o.get<int64_t>());
2777 return true;
2778 }
2779
2780 return false;
2781 #endif
2782 }
2783
2784 #ifdef TINYGLTF_USE_RAPIDJSON
2785 bool GetDouble(const json &o, double &val) {
2786 if (o.IsDouble()) {
2787 val = o.GetDouble();
2788 return true;
2789 }
2790
2791 return false;
2792 }
2793 #endif
2794
2795 bool GetNumber(const json &o, double &val) {
2796 #ifdef TINYGLTF_USE_RAPIDJSON
2797 if (o.IsNumber()) {
2798 val = o.GetDouble();
2799 return true;
2800 }
2801
2802 return false;
2803 #else
2804 if (o.is_number()) {
2805 val = o.get<double>();
2806 return true;
2807 }
2808
2809 return false;
2810 #endif
2811 }
2812
2813 bool GetString(const json &o, std::string &val) {
2814 #ifdef TINYGLTF_USE_RAPIDJSON
2815 if (o.IsString()) {
2816 val = o.GetString();
2817 return true;
2818 }
2819
2820 return false;
2821 #else
2822 if (o.type() == json::value_t::string) {
2823 val = o.get<std::string>();
2824 return true;
2825 }
2826
2827 return false;
2828 #endif
2829 }
2830
2831 bool IsArray(const json &o) {
2832 #ifdef TINYGLTF_USE_RAPIDJSON
2833 return o.IsArray();
2834 #else
2835 return o.is_array();
2836 #endif
2837 }
2838
2839 json_const_array_iterator ArrayBegin(const json &o) {
2840 #ifdef TINYGLTF_USE_RAPIDJSON
2841 return o.Begin();
2842 #else
2843 return o.begin();
2844 #endif
2845 }
2846
2847 json_const_array_iterator ArrayEnd(const json &o) {
2848 #ifdef TINYGLTF_USE_RAPIDJSON
2849 return o.End();
2850 #else
2851 return o.end();
2852 #endif
2853 }
2854
2855 bool IsObject(const json &o) {
2856 #ifdef TINYGLTF_USE_RAPIDJSON
2857 return o.IsObject();
2858 #else
2859 return o.is_object();
2860 #endif
2861 }
2862
2863 json_const_iterator ObjectBegin(const json &o) {
2864 #ifdef TINYGLTF_USE_RAPIDJSON
2865 return o.MemberBegin();
2866 #else
2867 return o.begin();
2868 #endif
2869 }
2870
2871 json_const_iterator ObjectEnd(const json &o) {
2872 #ifdef TINYGLTF_USE_RAPIDJSON
2873 return o.MemberEnd();
2874 #else
2875 return o.end();
2876 #endif
2877 }
2878
2879 const char *GetKey(json_const_iterator &it) {
2880 #ifdef TINYGLTF_USE_RAPIDJSON
2881 return it->name.GetString();
2882 #else
2883 return it.key().c_str();
2884 #endif
2885 }
2886
2887 bool FindMember(const json &o, const char *member, json_const_iterator &it) {
2888 #ifdef TINYGLTF_USE_RAPIDJSON
2889 if (!o.IsObject()) {
2890 return false;
2891 }
2892 it = o.FindMember(member);
2893 return it != o.MemberEnd();
2894 #else
2895 it = o.find(member);
2896 return it != o.end();
2897 #endif
2898 }
2899
2900 const json &GetValue(json_const_iterator &it) {
2901 #ifdef TINYGLTF_USE_RAPIDJSON
2902 return it->value;
2903 #else
2904 return it.value();
2905 #endif
2906 }
2907
2908 std::string JsonToString(const json &o, int spacing = -1) {
2909 #ifdef TINYGLTF_USE_RAPIDJSON
2910 using namespace rapidjson;
2911 StringBuffer buffer;
2912 if (spacing == -1) {
2913 Writer<StringBuffer> writer(buffer);
2914 o.Accept(writer);
2915 } else {
2916 PrettyWriter<StringBuffer> writer(buffer);
2917 writer.SetIndent(' ', uint32_t(spacing));
2918 o.Accept(writer);
2919 }
2920 return buffer.GetString();
2921 #else
2922 return o.dump(spacing);
2923 #endif
2924 }
2925
2926 } // namespace
2927
21862928 static bool ParseJsonAsValue(Value *ret, const json &o) {
21872929 Value val{};
2930 #ifdef TINYGLTF_USE_RAPIDJSON
2931 using rapidjson::Type;
2932 switch (o.GetType()) {
2933 case Type::kObjectType: {
2934 Value::Object value_object;
2935 for (auto it = o.MemberBegin(); it != o.MemberEnd(); ++it) {
2936 Value entry;
2937 ParseJsonAsValue(&entry, it->value);
2938 if (entry.Type() != NULL_TYPE)
2939 value_object.emplace(GetKey(it), std::move(entry));
2940 }
2941 if (value_object.size() > 0) val = Value(std::move(value_object));
2942 } break;
2943 case Type::kArrayType: {
2944 Value::Array value_array;
2945 value_array.reserve(o.Size());
2946 for (auto it = o.Begin(); it != o.End(); ++it) {
2947 Value entry;
2948 ParseJsonAsValue(&entry, *it);
2949 if (entry.Type() != NULL_TYPE)
2950 value_array.emplace_back(std::move(entry));
2951 }
2952 if (value_array.size() > 0) val = Value(std::move(value_array));
2953 } break;
2954 case Type::kStringType:
2955 val = Value(std::string(o.GetString()));
2956 break;
2957 case Type::kFalseType:
2958 case Type::kTrueType:
2959 val = Value(o.GetBool());
2960 break;
2961 case Type::kNumberType:
2962 if (!o.IsDouble()) {
2963 int i = 0;
2964 GetInt(o, i);
2965 val = Value(i);
2966 } else {
2967 double d = 0.0;
2968 GetDouble(o, d);
2969 val = Value(d);
2970 }
2971 break;
2972 case Type::kNullType:
2973 break;
2974 // all types are covered, so no `case default`
2975 }
2976 #else
21882977 switch (o.type()) {
21892978 case json::value_t::object: {
21902979 Value::Object value_object;
21912980 for (auto it = o.begin(); it != o.end(); it++) {
21922981 Value entry;
21932982 ParseJsonAsValue(&entry, it.value());
2194 if (entry.Type() != NULL_TYPE) value_object[it.key()] = entry;
2195 }
2196 if (value_object.size() > 0) val = Value(value_object);
2983 if (entry.Type() != NULL_TYPE)
2984 value_object.emplace(it.key(), std::move(entry));
2985 }
2986 if (value_object.size() > 0) val = Value(std::move(value_object));
21972987 } break;
21982988 case json::value_t::array: {
21992989 Value::Array value_array;
2990 value_array.reserve(o.size());
22002991 for (auto it = o.begin(); it != o.end(); it++) {
22012992 Value entry;
22022993 ParseJsonAsValue(&entry, it.value());
2203 if (entry.Type() != NULL_TYPE) value_array.push_back(entry);
2204 }
2205 if (value_array.size() > 0) val = Value(value_array);
2994 if (entry.Type() != NULL_TYPE)
2995 value_array.emplace_back(std::move(entry));
2996 }
2997 if (value_array.size() > 0) val = Value(std::move(value_array));
22062998 } break;
22072999 case json::value_t::string:
22083000 val = Value(o.get<std::string>());
22223014 // default:
22233015 break;
22243016 }
2225 if (ret) *ret = val;
3017 #endif
3018 if (ret) *ret = std::move(val);
22263019
22273020 return val.Type() != NULL_TYPE;
22283021 }
22293022
22303023 static bool ParseExtrasProperty(Value *ret, const json &o) {
2231 json::const_iterator it = o.find("extras");
2232 if (it == o.end()) {
2233 return false;
2234 }
2235
2236 return ParseJsonAsValue(ret, it.value());
3024 json_const_iterator it;
3025 if (!FindMember(o, "extras", it)) {
3026 return false;
3027 }
3028
3029 return ParseJsonAsValue(ret, GetValue(it));
22373030 }
22383031
22393032 static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o,
22403033 const std::string &property,
22413034 const bool required,
22423035 const std::string &parent_node = "") {
2243 json::const_iterator it = o.find(property);
2244 if (it == o.end()) {
3036 json_const_iterator it;
3037 if (!FindMember(o, property.c_str(), it)) {
22453038 if (required) {
22463039 if (err) {
22473040 (*err) += "'" + property + "' property is missing";
22543047 return false;
22553048 }
22563049
2257 if (!it.value().is_boolean()) {
3050 auto &value = GetValue(it);
3051
3052 bool isBoolean;
3053 bool boolValue = false;
3054 #ifdef TINYGLTF_USE_RAPIDJSON
3055 isBoolean = value.IsBool();
3056 if (isBoolean) {
3057 boolValue = value.GetBool();
3058 }
3059 #else
3060 isBoolean = value.is_boolean();
3061 if (isBoolean) {
3062 boolValue = value.get<bool>();
3063 }
3064 #endif
3065 if (!isBoolean) {
22583066 if (required) {
22593067 if (err) {
22603068 (*err) += "'" + property + "' property is not a bool type.\n";
22643072 }
22653073
22663074 if (ret) {
2267 (*ret) = it.value().get<bool>();
3075 (*ret) = boolValue;
22683076 }
22693077
22703078 return true;
22713079 }
22723080
2273 static bool ParseNumberProperty(double *ret, std::string *err, const json &o,
2274 const std::string &property,
2275 const bool required,
2276 const std::string &parent_node = "") {
2277 json::const_iterator it = o.find(property);
2278 if (it == o.end()) {
3081 static bool ParseIntegerProperty(int *ret, std::string *err, const json &o,
3082 const std::string &property,
3083 const bool required,
3084 const std::string &parent_node = "") {
3085 json_const_iterator it;
3086 if (!FindMember(o, property.c_str(), it)) {
22793087 if (required) {
22803088 if (err) {
22813089 (*err) += "'" + property + "' property is missing";
22883096 return false;
22893097 }
22903098
2291 if (!it.value().is_number()) {
3099 int intValue;
3100 bool isInt = GetInt(GetValue(it), intValue);
3101 if (!isInt) {
22923102 if (required) {
22933103 if (err) {
2294 (*err) += "'" + property + "' property is not a number type.\n";
3104 (*err) += "'" + property + "' property is not an integer type.\n";
22953105 }
22963106 }
22973107 return false;
22983108 }
22993109
23003110 if (ret) {
2301 (*ret) = it.value().get<double>();
3111 (*ret) = intValue;
23023112 }
23033113
23043114 return true;
23053115 }
23063116
2307 static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
2308 const json &o, const std::string &property,
2309 bool required,
2310 const std::string &parent_node = "") {
2311 json::const_iterator it = o.find(property);
2312 if (it == o.end()) {
3117 static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o,
3118 const std::string &property,
3119 const bool required,
3120 const std::string &parent_node = "") {
3121 json_const_iterator it;
3122 if (!FindMember(o, property.c_str(), it)) {
23133123 if (required) {
23143124 if (err) {
23153125 (*err) += "'" + property + "' property is missing";
23223132 return false;
23233133 }
23243134
2325 if (!it.value().is_array()) {
3135 auto &value = GetValue(it);
3136
3137 size_t uValue = 0;
3138 bool isUValue;
3139 #ifdef TINYGLTF_USE_RAPIDJSON
3140 isUValue = false;
3141 if (value.IsUint()) {
3142 uValue = value.GetUint();
3143 isUValue = true;
3144 } else if (value.IsUint64()) {
3145 uValue = value.GetUint64();
3146 isUValue = true;
3147 }
3148 #else
3149 isUValue = value.is_number_unsigned();
3150 if (isUValue) {
3151 uValue = value.get<size_t>();
3152 }
3153 #endif
3154 if (!isUValue) {
3155 if (required) {
3156 if (err) {
3157 (*err) += "'" + property + "' property is not a positive integer.\n";
3158 }
3159 }
3160 return false;
3161 }
3162
3163 if (ret) {
3164 (*ret) = uValue;
3165 }
3166
3167 return true;
3168 }
3169
3170 static bool ParseNumberProperty(double *ret, std::string *err, const json &o,
3171 const std::string &property,
3172 const bool required,
3173 const std::string &parent_node = "") {
3174 json_const_iterator it;
3175
3176 if (!FindMember(o, property.c_str(), it)) {
3177 if (required) {
3178 if (err) {
3179 (*err) += "'" + property + "' property is missing";
3180 if (!parent_node.empty()) {
3181 (*err) += " in " + parent_node;
3182 }
3183 (*err) += ".\n";
3184 }
3185 }
3186 return false;
3187 }
3188
3189 double numberValue;
3190 bool isNumber = GetNumber(GetValue(it), numberValue);
3191
3192 if (!isNumber) {
3193 if (required) {
3194 if (err) {
3195 (*err) += "'" + property + "' property is not a number type.\n";
3196 }
3197 }
3198 return false;
3199 }
3200
3201 if (ret) {
3202 (*ret) = numberValue;
3203 }
3204
3205 return true;
3206 }
3207
3208 static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
3209 const json &o, const std::string &property,
3210 bool required,
3211 const std::string &parent_node = "") {
3212 json_const_iterator it;
3213 if (!FindMember(o, property.c_str(), it)) {
3214 if (required) {
3215 if (err) {
3216 (*err) += "'" + property + "' property is missing";
3217 if (!parent_node.empty()) {
3218 (*err) += " in " + parent_node;
3219 }
3220 (*err) += ".\n";
3221 }
3222 }
3223 return false;
3224 }
3225
3226 if (!IsArray(GetValue(it))) {
23263227 if (required) {
23273228 if (err) {
23283229 (*err) += "'" + property + "' property is not an array";
23363237 }
23373238
23383239 ret->clear();
2339 for (json::const_iterator i = it.value().begin(); i != it.value().end();
2340 i++) {
2341 if (!i.value().is_number()) {
3240 auto end = ArrayEnd(GetValue(it));
3241 for (auto i = ArrayBegin(GetValue(it)); i != end; ++i) {
3242 double numberValue;
3243 const bool isNumber = GetNumber(*i, numberValue);
3244 if (!isNumber) {
23423245 if (required) {
23433246 if (err) {
23443247 (*err) += "'" + property + "' property is not a number.\n";
23503253 }
23513254 return false;
23523255 }
2353 ret->push_back(i.value());
3256 ret->push_back(numberValue);
3257 }
3258
3259 return true;
3260 }
3261
3262 static bool ParseIntegerArrayProperty(std::vector<int> *ret, std::string *err,
3263 const json &o,
3264 const std::string &property,
3265 bool required,
3266 const std::string &parent_node = "") {
3267 json_const_iterator it;
3268 if (!FindMember(o, property.c_str(), it)) {
3269 if (required) {
3270 if (err) {
3271 (*err) += "'" + property + "' property is missing";
3272 if (!parent_node.empty()) {
3273 (*err) += " in " + parent_node;
3274 }
3275 (*err) += ".\n";
3276 }
3277 }
3278 return false;
3279 }
3280
3281 if (!IsArray(GetValue(it))) {
3282 if (required) {
3283 if (err) {
3284 (*err) += "'" + property + "' property is not an array";
3285 if (!parent_node.empty()) {
3286 (*err) += " in " + parent_node;
3287 }
3288 (*err) += ".\n";
3289 }
3290 }
3291 return false;
3292 }
3293
3294 ret->clear();
3295 auto end = ArrayEnd(GetValue(it));
3296 for (auto i = ArrayBegin(GetValue(it)); i != end; ++i) {
3297 int numberValue;
3298 bool isNumber = GetInt(*i, numberValue);
3299 if (!isNumber) {
3300 if (required) {
3301 if (err) {
3302 (*err) += "'" + property + "' property is not an integer type.\n";
3303 if (!parent_node.empty()) {
3304 (*err) += " in " + parent_node;
3305 }
3306 (*err) += ".\n";
3307 }
3308 }
3309 return false;
3310 }
3311 ret->push_back(numberValue);
23543312 }
23553313
23563314 return true;
23603318 std::string *ret, std::string *err, const json &o,
23613319 const std::string &property, bool required,
23623320 const std::string &parent_node = std::string()) {
2363 json::const_iterator it = o.find(property);
2364 if (it == o.end()) {
3321 json_const_iterator it;
3322 if (!FindMember(o, property.c_str(), it)) {
23653323 if (required) {
23663324 if (err) {
23673325 (*err) += "'" + property + "' property is missing";
23753333 return false;
23763334 }
23773335
2378 if (!it.value().is_string()) {
3336 std::string strValue;
3337 if (!GetString(GetValue(it), strValue)) {
23793338 if (required) {
23803339 if (err) {
23813340 (*err) += "'" + property + "' property is not a string type.\n";
23853344 }
23863345
23873346 if (ret) {
2388 (*ret) = it.value().get<std::string>();
3347 (*ret) = std::move(strValue);
23893348 }
23903349
23913350 return true;
23923351 }
23933352
2394 static bool ParseStringIntProperty(std::map<std::string, int> *ret,
2395 std::string *err, const json &o,
2396 const std::string &property, bool required,
2397 const std::string &parent = "") {
2398 json::const_iterator it = o.find(property);
2399 if (it == o.end()) {
3353 static bool ParseStringIntegerProperty(std::map<std::string, int> *ret,
3354 std::string *err, const json &o,
3355 const std::string &property,
3356 bool required,
3357 const std::string &parent = "") {
3358 json_const_iterator it;
3359 if (!FindMember(o, property.c_str(), it)) {
24003360 if (required) {
24013361 if (err) {
24023362 if (!parent.empty()) {
24103370 return false;
24113371 }
24123372
3373 const json &dict = GetValue(it);
3374
24133375 // Make sure we are dealing with an object / dictionary.
2414 if (!it.value().is_object()) {
3376 if (!IsObject(dict)) {
24153377 if (required) {
24163378 if (err) {
24173379 (*err) += "'" + property + "' property is not an object.\n";
24213383 }
24223384
24233385 ret->clear();
2424 const json &dict = it.value();
2425
2426 json::const_iterator dictIt(dict.begin());
2427 json::const_iterator dictItEnd(dict.end());
3386
3387 json_const_iterator dictIt(ObjectBegin(dict));
3388 json_const_iterator dictItEnd(ObjectEnd(dict));
24283389
24293390 for (; dictIt != dictItEnd; ++dictIt) {
2430 if (!dictIt.value().is_number()) {
3391 int intVal;
3392 if (!GetInt(GetValue(dictIt), intVal)) {
24313393 if (required) {
24323394 if (err) {
2433 (*err) += "'" + property + "' value is not an int.\n";
3395 (*err) += "'" + property + "' value is not an integer type.\n";
24343396 }
24353397 }
24363398 return false;
24373399 }
24383400
24393401 // Insert into the list.
2440 (*ret)[dictIt.key()] = static_cast<int>(dictIt.value());
3402 (*ret)[GetKey(dictIt)] = intVal;
24413403 }
24423404 return true;
24433405 }
24453407 static bool ParseJSONProperty(std::map<std::string, double> *ret,
24463408 std::string *err, const json &o,
24473409 const std::string &property, bool required) {
2448 json::const_iterator it = o.find(property);
2449 if (it == o.end()) {
3410 json_const_iterator it;
3411 if (!FindMember(o, property.c_str(), it)) {
24503412 if (required) {
24513413 if (err) {
24523414 (*err) += "'" + property + "' property is missing. \n'";
24553417 return false;
24563418 }
24573419
2458 if (!it.value().is_object()) {
3420 const json &obj = GetValue(it);
3421
3422 if (!IsObject(obj)) {
24593423 if (required) {
24603424 if (err) {
24613425 (*err) += "'" + property + "' property is not a JSON object.\n";
24653429 }
24663430
24673431 ret->clear();
2468 const json &obj = it.value();
2469 json::const_iterator it2(obj.begin());
2470 json::const_iterator itEnd(obj.end());
2471 for (; it2 != itEnd; it2++) {
2472 if (it2.value().is_number())
2473 ret->insert(std::pair<std::string, double>(it2.key(), it2.value()));
3432
3433 json_const_iterator it2(ObjectBegin(obj));
3434 json_const_iterator itEnd(ObjectEnd(obj));
3435 for (; it2 != itEnd; ++it2) {
3436 double numVal;
3437 if (GetNumber(GetValue(it2), numVal))
3438 ret->emplace(std::string(GetKey(it2)), numVal);
24743439 }
24753440
24763441 return true;
25123477 const json &o) {
25133478 (void)err;
25143479
2515 json::const_iterator it = o.find("extensions");
2516 if (it == o.end()) {
2517 return false;
2518 }
2519 if (!it.value().is_object()) {
3480 json_const_iterator it;
3481 if (!FindMember(o, "extensions", it)) {
3482 return false;
3483 }
3484
3485 auto &obj = GetValue(it);
3486 if (!IsObject(obj)) {
25203487 return false;
25213488 }
25223489 ExtensionMap extensions;
2523 json::const_iterator extIt = it.value().begin();
2524 for (; extIt != it.value().end(); extIt++) {
2525 if (!extIt.value().is_object()) continue;
2526 if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) {
2527 if (!extIt.key().empty()) {
3490 json_const_iterator extIt = ObjectBegin(obj); // it.value().begin();
3491 json_const_iterator extEnd = ObjectEnd(obj);
3492 for (; extIt != extEnd; ++extIt) {
3493 auto &itObj = GetValue(extIt);
3494 if (!IsObject(itObj)) continue;
3495 std::string key(GetKey(extIt));
3496 if (!ParseJsonAsValue(&extensions[key], itObj)) {
3497 if (!key.empty()) {
25283498 // create empty object so that an extension object is still of type
25293499 // object
2530 extensions[extIt.key()] = Value{Value::Object{}};
3500 extensions[key] = Value{Value::Object{}};
25313501 }
25323502 }
25333503 }
25343504 if (ret) {
2535 (*ret) = extensions;
3505 (*ret) = std::move(extensions);
25363506 }
25373507 return true;
25383508 }
25393509
2540 static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
3510 static bool ParseAsset(Asset *asset, std::string *err, const json &o,
3511 bool store_original_json_for_extras_and_extensions) {
25413512 ParseStringProperty(&asset->version, err, o, "version", true, "Asset");
25423513 ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset");
25433514 ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset");
3515 ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset");
25443516
25453517 ParseExtensionsProperty(&asset->extensions, err, o);
25463518
25473519 // Unity exporter version is added as extra here
25483520 ParseExtrasProperty(&(asset->extras), o);
25493521
3522 if (store_original_json_for_extras_and_extensions) {
3523 {
3524 json_const_iterator it;
3525 if (FindMember(o, "extensions", it)) {
3526 asset->extensions_json_string = JsonToString(GetValue(it));
3527 }
3528 }
3529 {
3530 json_const_iterator it;
3531 if (FindMember(o, "extras", it)) {
3532 asset->extras_json_string = JsonToString(GetValue(it));
3533 }
3534 }
3535 }
3536
25503537 return true;
25513538 }
25523539
25533540 static bool ParseImage(Image *image, const int image_idx, std::string *err,
25543541 std::string *warn, const json &o,
3542 bool store_original_json_for_extras_and_extensions,
25553543 const std::string &basedir, FsCallbacks *fs,
25563544 LoadImageDataFunction *LoadImageData = nullptr,
25573545 void *load_image_user_data = nullptr) {
25593547
25603548 // schema says oneOf [`bufferView`, `uri`]
25613549 // TODO(syoyo): Check the type of each parameters.
2562 bool hasBufferView = (o.find("bufferView") != o.end());
2563 bool hasURI = (o.find("uri") != o.end());
3550 json_const_iterator it;
3551 bool hasBufferView = FindMember(o, "bufferView", it);
3552 bool hasURI = FindMember(o, "uri", it);
25643553
25653554 ParseStringProperty(&image->name, err, o, "name", false);
25663555
25873576 ParseExtensionsProperty(&image->extensions, err, o);
25883577 ParseExtrasProperty(&image->extras, o);
25893578
3579 if (store_original_json_for_extras_and_extensions) {
3580 {
3581 json_const_iterator eit;
3582 if (FindMember(o, "extensions", eit)) {
3583 image->extensions_json_string = JsonToString(GetValue(eit));
3584 }
3585 }
3586 {
3587 json_const_iterator eit;
3588 if (FindMember(o, "extras", eit)) {
3589 image->extras_json_string = JsonToString(GetValue(eit));
3590 }
3591 }
3592 }
3593
25903594 if (hasBufferView) {
2591 double bufferView = -1;
2592 if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
3595 int bufferView = -1;
3596 if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) {
25933597 if (err) {
25943598 (*err) += "Failed to parse `bufferView` for image[" +
25953599 std::to_string(image_idx) + "] name = \"" + image->name +
26013605 std::string mime_type;
26023606 ParseStringProperty(&mime_type, err, o, "mimeType", false);
26033607
2604 double width = 0.0;
2605 ParseNumberProperty(&width, err, o, "width", false);
2606
2607 double height = 0.0;
2608 ParseNumberProperty(&height, err, o, "height", false);
3608 int width = 0;
3609 ParseIntegerProperty(&width, err, o, "width", false);
3610
3611 int height = 0;
3612 ParseIntegerProperty(&height, err, o, "height", false);
26093613
26103614 // Just only save some information here. Loading actual image data from
26113615 // bufferView is done after this `ParseImage` function.
2612 image->bufferView = static_cast<int>(bufferView);
3616 image->bufferView = bufferView;
26133617 image->mimeType = mime_type;
2614 image->width = static_cast<int>(width);
2615 image->height = static_cast<int>(height);
3618 image->width = width;
3619 image->height = height;
26163620
26173621 return true;
26183622 }
26783682 }
26793683
26803684 static bool ParseTexture(Texture *texture, std::string *err, const json &o,
3685 bool store_original_json_for_extras_and_extensions,
26813686 const std::string &basedir) {
26823687 (void)basedir;
2683 double sampler = -1.0;
2684 double source = -1.0;
2685 ParseNumberProperty(&sampler, err, o, "sampler", false);
2686
2687 ParseNumberProperty(&source, err, o, "source", false);
2688
2689 texture->sampler = static_cast<int>(sampler);
2690 texture->source = static_cast<int>(source);
3688 int sampler = -1;
3689 int source = -1;
3690 ParseIntegerProperty(&sampler, err, o, "sampler", false);
3691
3692 ParseIntegerProperty(&source, err, o, "source", false);
3693
3694 texture->sampler = sampler;
3695 texture->source = source;
26913696
26923697 ParseExtensionsProperty(&texture->extensions, err, o);
26933698 ParseExtrasProperty(&texture->extras, o);
26943699
3700 if (store_original_json_for_extras_and_extensions) {
3701 {
3702 json_const_iterator it;
3703 if (FindMember(o, "extensions", it)) {
3704 texture->extensions_json_string = JsonToString(GetValue(it));
3705 }
3706 }
3707 {
3708 json_const_iterator it;
3709 if (FindMember(o, "extras", it)) {
3710 texture->extras_json_string = JsonToString(GetValue(it));
3711 }
3712 }
3713 }
3714
26953715 ParseStringProperty(&texture->name, err, o, "name", false);
26963716
26973717 return true;
26983718 }
26993719
3720 static bool ParseTextureInfo(
3721 TextureInfo *texinfo, std::string *err, const json &o,
3722 bool store_original_json_for_extras_and_extensions) {
3723 if (texinfo == nullptr) {
3724 return false;
3725 }
3726
3727 if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
3728 /* required */ true, "TextureInfo")) {
3729 return false;
3730 }
3731
3732 ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
3733
3734 ParseExtensionsProperty(&texinfo->extensions, err, o);
3735 ParseExtrasProperty(&texinfo->extras, o);
3736
3737 if (store_original_json_for_extras_and_extensions) {
3738 {
3739 json_const_iterator it;
3740 if (FindMember(o, "extensions", it)) {
3741 texinfo->extensions_json_string = JsonToString(GetValue(it));
3742 }
3743 }
3744 {
3745 json_const_iterator it;
3746 if (FindMember(o, "extras", it)) {
3747 texinfo->extras_json_string = JsonToString(GetValue(it));
3748 }
3749 }
3750 }
3751
3752 return true;
3753 }
3754
3755 static bool ParseNormalTextureInfo(
3756 NormalTextureInfo *texinfo, std::string *err, const json &o,
3757 bool store_original_json_for_extras_and_extensions) {
3758 if (texinfo == nullptr) {
3759 return false;
3760 }
3761
3762 if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
3763 /* required */ true, "NormalTextureInfo")) {
3764 return false;
3765 }
3766
3767 ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
3768 ParseNumberProperty(&texinfo->scale, err, o, "scale", false);
3769
3770 ParseExtensionsProperty(&texinfo->extensions, err, o);
3771 ParseExtrasProperty(&texinfo->extras, o);
3772
3773 if (store_original_json_for_extras_and_extensions) {
3774 {
3775 json_const_iterator it;
3776 if (FindMember(o, "extensions", it)) {
3777 texinfo->extensions_json_string = JsonToString(GetValue(it));
3778 }
3779 }
3780 {
3781 json_const_iterator it;
3782 if (FindMember(o, "extras", it)) {
3783 texinfo->extras_json_string = JsonToString(GetValue(it));
3784 }
3785 }
3786 }
3787
3788 return true;
3789 }
3790
3791 static bool ParseOcclusionTextureInfo(
3792 OcclusionTextureInfo *texinfo, std::string *err, const json &o,
3793 bool store_original_json_for_extras_and_extensions) {
3794 if (texinfo == nullptr) {
3795 return false;
3796 }
3797
3798 if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
3799 /* required */ true, "NormalTextureInfo")) {
3800 return false;
3801 }
3802
3803 ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
3804 ParseNumberProperty(&texinfo->strength, err, o, "strength", false);
3805
3806 ParseExtensionsProperty(&texinfo->extensions, err, o);
3807 ParseExtrasProperty(&texinfo->extras, o);
3808
3809 if (store_original_json_for_extras_and_extensions) {
3810 {
3811 json_const_iterator it;
3812 if (FindMember(o, "extensions", it)) {
3813 texinfo->extensions_json_string = JsonToString(GetValue(it));
3814 }
3815 }
3816 {
3817 json_const_iterator it;
3818 if (FindMember(o, "extras", it)) {
3819 texinfo->extras_json_string = JsonToString(GetValue(it));
3820 }
3821 }
3822 }
3823
3824 return true;
3825 }
3826
27003827 static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
3828 bool store_original_json_for_extras_and_extensions,
27013829 FsCallbacks *fs, const std::string &basedir,
27023830 bool is_binary = false,
27033831 const unsigned char *bin_data = nullptr,
27043832 size_t bin_size = 0) {
2705 double byteLength;
2706 if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true, "Buffer")) {
3833 size_t byteLength;
3834 if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
3835 "Buffer")) {
27073836 return false;
27083837 }
27093838
27183847 }
27193848 }
27203849
2721 json::const_iterator type = o.find("type");
2722 if (type != o.end()) {
2723 if (type.value().is_string()) {
2724 const std::string &ty = type.value();
2725 if (ty.compare("arraybuffer") == 0) {
3850 json_const_iterator type;
3851 if (FindMember(o, "type", type)) {
3852 std::string typeStr;
3853 if (GetString(GetValue(type), typeStr)) {
3854 if (typeStr.compare("arraybuffer") == 0) {
27263855 // buffer.type = "arraybuffer";
27273856 }
27283857 }
27293858 }
27303859
2731 size_t bytes = static_cast<size_t>(byteLength);
27323860 if (is_binary) {
27333861 // Still binary glTF accepts external dataURI.
27343862 if (!buffer->uri.empty()) {
27353863 // First try embedded data URI.
27363864 if (IsDataURI(buffer->uri)) {
27373865 std::string mime_type;
2738 if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes,
3866 if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
27393867 true)) {
27403868 if (err) {
27413869 (*err) +=
27463874 } else {
27473875 // External .bin file.
27483876 if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
2749 buffer->uri, basedir, true, bytes, true, fs)) {
3877 buffer->uri, basedir, true, byteLength, true,
3878 fs)) {
27503879 return false;
27513880 }
27523881 }
27793908 } else {
27803909 if (IsDataURI(buffer->uri)) {
27813910 std::string mime_type;
2782 if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes, true)) {
3911 if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
3912 true)) {
27833913 if (err) {
27843914 (*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
27853915 }
27883918 } else {
27893919 // Assume external .bin file.
27903920 if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
2791 basedir, true, bytes, true, fs)) {
3921 basedir, true, byteLength, true, fs)) {
27923922 return false;
27933923 }
27943924 }
27963926
27973927 ParseStringProperty(&buffer->name, err, o, "name", false);
27983928
3929 ParseExtensionsProperty(&buffer->extensions, err, o);
3930 ParseExtrasProperty(&buffer->extras, o);
3931
3932 if (store_original_json_for_extras_and_extensions) {
3933 {
3934 json_const_iterator it;
3935 if (FindMember(o, "extensions", it)) {
3936 buffer->extensions_json_string = JsonToString(GetValue(it));
3937 }
3938 }
3939 {
3940 json_const_iterator it;
3941 if (FindMember(o, "extras", it)) {
3942 buffer->extras_json_string = JsonToString(GetValue(it));
3943 }
3944 }
3945 }
3946
27993947 return true;
28003948 }
28013949
2802 static bool ParseBufferView(BufferView *bufferView, std::string *err,
2803 const json &o) {
2804 double buffer = -1.0;
2805 if (!ParseNumberProperty(&buffer, err, o, "buffer", true, "BufferView")) {
2806 return false;
2807 }
2808
2809 double byteOffset = 0.0;
2810 ParseNumberProperty(&byteOffset, err, o, "byteOffset", false);
2811
2812 double byteLength = 1.0;
2813 if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true,
2814 "BufferView")) {
3950 static bool ParseBufferView(
3951 BufferView *bufferView, std::string *err, const json &o,
3952 bool store_original_json_for_extras_and_extensions) {
3953 int buffer = -1;
3954 if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) {
3955 return false;
3956 }
3957
3958 size_t byteOffset = 0;
3959 ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false);
3960
3961 size_t byteLength = 1;
3962 if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
3963 "BufferView")) {
28153964 return false;
28163965 }
28173966
28183967 size_t byteStride = 0;
2819 double byteStrideValue = 0.0;
2820 if (!ParseNumberProperty(&byteStrideValue, err, o, "byteStride", false)) {
3968 if (!ParseUnsignedProperty(&byteStride, err, o, "byteStride", false)) {
28213969 // Spec says: When byteStride of referenced bufferView is not defined, it
28223970 // means that accessor elements are tightly packed, i.e., effective stride
28233971 // equals the size of the element.
28243972 // We cannot determine the actual byteStride until Accessor are parsed, thus
28253973 // set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner)
28263974 byteStride = 0;
2827 } else {
2828 byteStride = static_cast<size_t>(byteStrideValue);
28293975 }
28303976
28313977 if ((byteStride > 252) || ((byteStride % 4) != 0)) {
28403986 return false;
28413987 }
28423988
2843 double target = 0.0;
2844 ParseNumberProperty(&target, err, o, "target", false);
2845 int targetValue = static_cast<int>(target);
2846 if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) ||
2847 (targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
3989 int target = 0;
3990 ParseIntegerProperty(&target, err, o, "target", false);
3991 if ((target == TINYGLTF_TARGET_ARRAY_BUFFER) ||
3992 (target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
28483993 // OK
28493994 } else {
2850 targetValue = 0;
2851 }
2852 bufferView->target = targetValue;
3995 target = 0;
3996 }
3997 bufferView->target = target;
28533998
28543999 ParseStringProperty(&bufferView->name, err, o, "name", false);
28554000
2856 bufferView->buffer = static_cast<int>(buffer);
2857 bufferView->byteOffset = static_cast<size_t>(byteOffset);
2858 bufferView->byteLength = static_cast<size_t>(byteLength);
2859 bufferView->byteStride = static_cast<size_t>(byteStride);
4001 ParseExtensionsProperty(&bufferView->extensions, err, o);
4002 ParseExtrasProperty(&bufferView->extras, o);
4003
4004 if (store_original_json_for_extras_and_extensions) {
4005 {
4006 json_const_iterator it;
4007 if (FindMember(o, "extensions", it)) {
4008 bufferView->extensions_json_string = JsonToString(GetValue(it));
4009 }
4010 }
4011 {
4012 json_const_iterator it;
4013 if (FindMember(o, "extras", it)) {
4014 bufferView->extras_json_string = JsonToString(GetValue(it));
4015 }
4016 }
4017 }
4018
4019 bufferView->buffer = buffer;
4020 bufferView->byteOffset = byteOffset;
4021 bufferView->byteLength = byteLength;
4022 bufferView->byteStride = byteStride;
28604023 return true;
28614024 }
28624025
28644027 const json &o) {
28654028 accessor->sparse.isSparse = true;
28664029
2867 double count = 0.0;
2868 ParseNumberProperty(&count, err, o, "count", true);
2869
2870 const auto indices_iterator = o.find("indices");
2871 const auto values_iterator = o.find("values");
2872 if (indices_iterator == o.end()) {
4030 int count = 0;
4031 ParseIntegerProperty(&count, err, o, "count", true);
4032
4033 json_const_iterator indices_iterator;
4034 json_const_iterator values_iterator;
4035 if (!FindMember(o, "indices", indices_iterator)) {
28734036 (*err) = "the sparse object of this accessor doesn't have indices";
28744037 return false;
28754038 }
28764039
2877 if (values_iterator == o.end()) {
4040 if (!FindMember(o, "values", values_iterator)) {
28784041 (*err) = "the sparse object ob ths accessor doesn't have values";
28794042 return false;
28804043 }
28814044
2882 const json &indices_obj = *indices_iterator;
2883 const json &values_obj = *values_iterator;
2884
2885 double indices_buffer_view = 0.0, indices_byte_offset = 0.0,
2886 component_type = 0.0;
2887 ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView",
2888 true);
2889 ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
2890 true);
2891 ParseNumberProperty(&component_type, err, indices_obj, "componentType", true);
2892
2893 double values_buffer_view = 0.0, values_byte_offset = 0.0;
2894 ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true);
2895 ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true);
2896
2897 accessor->sparse.count = static_cast<int>(count);
2898 accessor->sparse.indices.bufferView = static_cast<int>(indices_buffer_view);
2899 accessor->sparse.indices.byteOffset = static_cast<int>(indices_byte_offset);
2900 accessor->sparse.indices.componentType = static_cast<int>(component_type);
2901 accessor->sparse.values.bufferView = static_cast<int>(values_buffer_view);
2902 accessor->sparse.values.byteOffset = static_cast<int>(values_byte_offset);
4045 const json &indices_obj = GetValue(indices_iterator);
4046 const json &values_obj = GetValue(values_iterator);
4047
4048 int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
4049 ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
4050 true);
4051 ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
4052 true);
4053 ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
4054 true);
4055
4056 int values_buffer_view = 0, values_byte_offset = 0;
4057 ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
4058 true);
4059 ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
4060 true);
4061
4062 accessor->sparse.count = count;
4063 accessor->sparse.indices.bufferView = indices_buffer_view;
4064 accessor->sparse.indices.byteOffset = indices_byte_offset;
4065 accessor->sparse.indices.componentType = component_type;
4066 accessor->sparse.values.bufferView = values_buffer_view;
4067 accessor->sparse.values.byteOffset = values_byte_offset;
29034068
29044069 // todo check theses values
29054070
29064071 return true;
29074072 }
29084073
2909 static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
2910 double bufferView = -1.0;
2911 ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
2912
2913 double byteOffset = 0.0;
2914 ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
4074 static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o,
4075 bool store_original_json_for_extras_and_extensions) {
4076 int bufferView = -1;
4077 ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor");
4078
4079 size_t byteOffset = 0;
4080 ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
29154081
29164082 bool normalized = false;
29174083 ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor");
29184084
2919 double componentType = 0.0;
2920 if (!ParseNumberProperty(&componentType, err, o, "componentType", true,
2921 "Accessor")) {
2922 return false;
2923 }
2924
2925 double count = 0.0;
2926 if (!ParseNumberProperty(&count, err, o, "count", true, "Accessor")) {
4085 size_t componentType = 0;
4086 if (!ParseUnsignedProperty(&componentType, err, o, "componentType", true,
4087 "Accessor")) {
4088 return false;
4089 }
4090
4091 size_t count = 0;
4092 if (!ParseUnsignedProperty(&count, err, o, "count", true, "Accessor")) {
29274093 return false;
29284094 }
29294095
29654131 ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false,
29664132 "Accessor");
29674133
2968 accessor->count = static_cast<size_t>(count);
2969 accessor->bufferView = static_cast<int>(bufferView);
2970 accessor->byteOffset = static_cast<size_t>(byteOffset);
4134 accessor->count = count;
4135 accessor->bufferView = bufferView;
4136 accessor->byteOffset = byteOffset;
29714137 accessor->normalized = normalized;
29724138 {
2973 int comp = static_cast<int>(componentType);
2974 if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE &&
2975 comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
4139 if (componentType >= TINYGLTF_COMPONENT_TYPE_BYTE &&
4140 componentType <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
29764141 // OK
2977 accessor->componentType = comp;
4142 accessor->componentType = int(componentType);
29784143 } else {
29794144 std::stringstream ss;
2980 ss << "Invalid `componentType` in accessor. Got " << comp << "\n";
4145 ss << "Invalid `componentType` in accessor. Got " << componentType
4146 << "\n";
29814147 if (err) {
29824148 (*err) += ss.str();
29834149 }
29854151 }
29864152 }
29874153
4154 ParseExtensionsProperty(&(accessor->extensions), err, o);
29884155 ParseExtrasProperty(&(accessor->extras), o);
29894156
4157 if (store_original_json_for_extras_and_extensions) {
4158 {
4159 json_const_iterator it;
4160 if (FindMember(o, "extensions", it)) {
4161 accessor->extensions_json_string = JsonToString(GetValue(it));
4162 }
4163 }
4164 {
4165 json_const_iterator it;
4166 if (FindMember(o, "extras", it)) {
4167 accessor->extras_json_string = JsonToString(GetValue(it));
4168 }
4169 }
4170 }
4171
29904172 // check if accessor has a "sparse" object:
2991 const auto iterator = o.find("sparse");
2992 if (iterator != o.end()) {
4173 json_const_iterator iterator;
4174 if (FindMember(o, "sparse", iterator)) {
29934175 // here this accessor has a "sparse" subobject
2994 return ParseSparseAccessor(accessor, err, *iterator);
4176 return ParseSparseAccessor(accessor, err, GetValue(iterator));
29954177 }
29964178
29974179 return true;
31904372 #endif
31914373
31924374 static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
3193 const json &o) {
3194 double material = -1.0;
3195 ParseNumberProperty(&material, err, o, "material", false);
3196 primitive->material = static_cast<int>(material);
3197
3198 double mode = static_cast<double>(TINYGLTF_MODE_TRIANGLES);
3199 ParseNumberProperty(&mode, err, o, "mode", false);
3200
3201 int primMode = static_cast<int>(mode);
3202 primitive->mode = primMode; // Why only triangled were supported ?
3203
3204 double indices = -1.0;
3205 ParseNumberProperty(&indices, err, o, "indices", false);
3206 primitive->indices = static_cast<int>(indices);
3207 if (!ParseStringIntProperty(&primitive->attributes, err, o, "attributes",
3208 true, "Primitive")) {
4375 const json &o,
4376 bool store_original_json_for_extras_and_extensions) {
4377 int material = -1;
4378 ParseIntegerProperty(&material, err, o, "material", false);
4379 primitive->material = material;
4380
4381 int mode = TINYGLTF_MODE_TRIANGLES;
4382 ParseIntegerProperty(&mode, err, o, "mode", false);
4383 primitive->mode = mode; // Why only triangled were supported ?
4384
4385 int indices = -1;
4386 ParseIntegerProperty(&indices, err, o, "indices", false);
4387 primitive->indices = indices;
4388 if (!ParseStringIntegerProperty(&primitive->attributes, err, o, "attributes",
4389 true, "Primitive")) {
32094390 return false;
32104391 }
32114392
32124393 // Look for morph targets
3213 json::const_iterator targetsObject = o.find("targets");
3214 if ((targetsObject != o.end()) && targetsObject.value().is_array()) {
3215 for (json::const_iterator i = targetsObject.value().begin();
3216 i != targetsObject.value().end(); i++) {
4394 json_const_iterator targetsObject;
4395 if (FindMember(o, "targets", targetsObject) &&
4396 IsArray(GetValue(targetsObject))) {
4397 auto targetsObjectEnd = ArrayEnd(GetValue(targetsObject));
4398 for (json_const_array_iterator i = ArrayBegin(GetValue(targetsObject));
4399 i != targetsObjectEnd; ++i) {
32174400 std::map<std::string, int> targetAttribues;
32184401
3219 const json &dict = i.value();
3220 json::const_iterator dictIt(dict.begin());
3221 json::const_iterator dictItEnd(dict.end());
3222
3223 for (; dictIt != dictItEnd; ++dictIt) {
3224 targetAttribues[dictIt.key()] = static_cast<int>(dictIt.value());
3225 }
3226 primitive->targets.push_back(targetAttribues);
4402 const json &dict = *i;
4403 if (IsObject(dict)) {
4404 json_const_iterator dictIt(ObjectBegin(dict));
4405 json_const_iterator dictItEnd(ObjectEnd(dict));
4406
4407 for (; dictIt != dictItEnd; ++dictIt) {
4408 int iVal;
4409 if (GetInt(GetValue(dictIt), iVal))
4410 targetAttribues[GetKey(dictIt)] = iVal;
4411 }
4412 primitive->targets.emplace_back(std::move(targetAttribues));
4413 }
32274414 }
32284415 }
32294416
32304417 ParseExtrasProperty(&(primitive->extras), o);
3231
32324418 ParseExtensionsProperty(&primitive->extensions, err, o);
4419
4420 if (store_original_json_for_extras_and_extensions) {
4421 {
4422 json_const_iterator it;
4423 if (FindMember(o, "extensions", it)) {
4424 primitive->extensions_json_string = JsonToString(GetValue(it));
4425 }
4426 }
4427 {
4428 json_const_iterator it;
4429 if (FindMember(o, "extras", it)) {
4430 primitive->extras_json_string = JsonToString(GetValue(it));
4431 }
4432 }
4433 }
32334434
32344435 #ifdef TINYGLTF_ENABLE_DRACO
32354436 auto dracoExtension =
32444445 return true;
32454446 }
32464447
3247 static bool ParseMesh(Mesh *mesh, Model *model, std::string *err,
3248 const json &o) {
4448 static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o,
4449 bool store_original_json_for_extras_and_extensions) {
32494450 ParseStringProperty(&mesh->name, err, o, "name", false);
32504451
32514452 mesh->primitives.clear();
3252 json::const_iterator primObject = o.find("primitives");
3253 if ((primObject != o.end()) && primObject.value().is_array()) {
3254 for (json::const_iterator i = primObject.value().begin();
3255 i != primObject.value().end(); i++) {
4453 json_const_iterator primObject;
4454 if (FindMember(o, "primitives", primObject) &&
4455 IsArray(GetValue(primObject))) {
4456 json_const_array_iterator primEnd = ArrayEnd(GetValue(primObject));
4457 for (json_const_array_iterator i = ArrayBegin(GetValue(primObject));
4458 i != primEnd; ++i) {
32564459 Primitive primitive;
3257 if (ParsePrimitive(&primitive, model, err, i.value())) {
4460 if (ParsePrimitive(&primitive, model, err, *i,
4461 store_original_json_for_extras_and_extensions)) {
32584462 // Only add the primitive if the parsing succeeds.
3259 mesh->primitives.push_back(primitive);
3260 }
3261 }
3262 }
3263
3264 // Look for morph targets
3265 json::const_iterator targetsObject = o.find("targets");
3266 if ((targetsObject != o.end()) && targetsObject.value().is_array()) {
3267 for (json::const_iterator i = targetsObject.value().begin();
3268 i != targetsObject.value().end(); i++) {
3269 std::map<std::string, int> targetAttribues;
3270
3271 const json &dict = i.value();
3272 json::const_iterator dictIt(dict.begin());
3273 json::const_iterator dictItEnd(dict.end());
3274
3275 for (; dictIt != dictItEnd; ++dictIt) {
3276 targetAttribues[dictIt.key()] = static_cast<int>(dictIt.value());
3277 }
3278 mesh->targets.push_back(targetAttribues);
4463 mesh->primitives.emplace_back(std::move(primitive));
4464 }
32794465 }
32804466 }
32814467
32854471 ParseExtensionsProperty(&mesh->extensions, err, o);
32864472 ParseExtrasProperty(&(mesh->extras), o);
32874473
4474 if (store_original_json_for_extras_and_extensions) {
4475 {
4476 json_const_iterator it;
4477 if (FindMember(o, "extensions", it)) {
4478 mesh->extensions_json_string = JsonToString(GetValue(it));
4479 }
4480 }
4481 {
4482 json_const_iterator it;
4483 if (FindMember(o, "extras", it)) {
4484 mesh->extras_json_string = JsonToString(GetValue(it));
4485 }
4486 }
4487 }
4488
32884489 return true;
32894490 }
32904491
3291 static bool ParseLight(Light *light, std::string *err, const json &o) {
3292 ParseStringProperty(&light->name, err, o, "name", false);
3293 ParseNumberArrayProperty(&light->color, err, o, "color", false);
3294 ParseStringProperty(&light->type, err, o, "type", false);
3295 return true;
3296 }
3297
3298 static bool ParseNode(Node *node, std::string *err, const json &o) {
4492 static bool ParseNode(Node *node, std::string *err, const json &o,
4493 bool store_original_json_for_extras_and_extensions) {
32994494 ParseStringProperty(&node->name, err, o, "name", false);
33004495
3301 double skin = -1.0;
3302 ParseNumberProperty(&skin, err, o, "skin", false);
3303 node->skin = static_cast<int>(skin);
4496 int skin = -1;
4497 ParseIntegerProperty(&skin, err, o, "skin", false);
4498 node->skin = skin;
33044499
33054500 // Matrix and T/R/S are exclusive
33064501 if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
33094504 ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
33104505 }
33114506
3312 double camera = -1.0;
3313 ParseNumberProperty(&camera, err, o, "camera", false);
3314 node->camera = static_cast<int>(camera);
3315
3316 double mesh = -1.0;
3317 ParseNumberProperty(&mesh, err, o, "mesh", false);
3318 node->mesh = int(mesh);
4507 int camera = -1;
4508 ParseIntegerProperty(&camera, err, o, "camera", false);
4509 node->camera = camera;
4510
4511 int mesh = -1;
4512 ParseIntegerProperty(&mesh, err, o, "mesh", false);
4513 node->mesh = mesh;
33194514
33204515 node->children.clear();
3321 json::const_iterator childrenObject = o.find("children");
3322 if ((childrenObject != o.end()) && childrenObject.value().is_array()) {
3323 for (json::const_iterator i = childrenObject.value().begin();
3324 i != childrenObject.value().end(); i++) {
3325 if (!i.value().is_number()) {
3326 if (err) {
3327 (*err) += "Invalid `children` array.\n";
3328 }
3329 return false;
3330 }
3331 const int &childrenNode = static_cast<int>(i.value());
3332 node->children.push_back(childrenNode);
3333 }
3334 }
4516 ParseIntegerArrayProperty(&node->children, err, o, "children", false);
4517
4518 ParseNumberArrayProperty(&node->weights, err, o, "weights", false);
33354519
33364520 ParseExtensionsProperty(&node->extensions, err, o);
33374521 ParseExtrasProperty(&(node->extras), o);
33384522
4523 if (store_original_json_for_extras_and_extensions) {
4524 {
4525 json_const_iterator it;
4526 if (FindMember(o, "extensions", it)) {
4527 node->extensions_json_string = JsonToString(GetValue(it));
4528 }
4529 }
4530 {
4531 json_const_iterator it;
4532 if (FindMember(o, "extras", it)) {
4533 node->extras_json_string = JsonToString(GetValue(it));
4534 }
4535 }
4536 }
4537
33394538 return true;
33404539 }
33414540
3342 static bool ParseMaterial(Material *material, std::string *err, const json &o) {
4541 static bool ParsePbrMetallicRoughness(
4542 PbrMetallicRoughness *pbr, std::string *err, const json &o,
4543 bool store_original_json_for_extras_and_extensions) {
4544 if (pbr == nullptr) {
4545 return false;
4546 }
4547
4548 std::vector<double> baseColorFactor;
4549 if (ParseNumberArrayProperty(&baseColorFactor, err, o, "baseColorFactor",
4550 /* required */ false)) {
4551 if (baseColorFactor.size() != 4) {
4552 if (err) {
4553 (*err) +=
4554 "Array length of `baseColorFactor` parameter in "
4555 "pbrMetallicRoughness must be 4, but got " +
4556 std::to_string(baseColorFactor.size()) + "\n";
4557 }
4558 return false;
4559 }
4560 pbr->baseColorFactor = baseColorFactor;
4561 }
4562
4563 {
4564 json_const_iterator it;
4565 if (FindMember(o, "baseColorTexture", it)) {
4566 ParseTextureInfo(&pbr->baseColorTexture, err, GetValue(it),
4567 store_original_json_for_extras_and_extensions);
4568 }
4569 }
4570
4571 {
4572 json_const_iterator it;
4573 if (FindMember(o, "metallicRoughnessTexture", it)) {
4574 ParseTextureInfo(&pbr->metallicRoughnessTexture, err, GetValue(it),
4575 store_original_json_for_extras_and_extensions);
4576 }
4577 }
4578
4579 ParseNumberProperty(&pbr->metallicFactor, err, o, "metallicFactor", false);
4580 ParseNumberProperty(&pbr->roughnessFactor, err, o, "roughnessFactor", false);
4581
4582 ParseExtensionsProperty(&pbr->extensions, err, o);
4583 ParseExtrasProperty(&pbr->extras, o);
4584
4585 if (store_original_json_for_extras_and_extensions) {
4586 {
4587 json_const_iterator it;
4588 if (FindMember(o, "extensions", it)) {
4589 pbr->extensions_json_string = JsonToString(GetValue(it));
4590 }
4591 }
4592 {
4593 json_const_iterator it;
4594 if (FindMember(o, "extras", it)) {
4595 pbr->extras_json_string = JsonToString(GetValue(it));
4596 }
4597 }
4598 }
4599
4600 return true;
4601 }
4602
4603 static bool ParseMaterial(Material *material, std::string *err, const json &o,
4604 bool store_original_json_for_extras_and_extensions) {
4605 ParseStringProperty(&material->name, err, o, "name", /* required */ false);
4606
4607 if (ParseNumberArrayProperty(&material->emissiveFactor, err, o,
4608 "emissiveFactor",
4609 /* required */ false)) {
4610 if (material->emissiveFactor.size() != 3) {
4611 if (err) {
4612 (*err) +=
4613 "Array length of `emissiveFactor` parameter in "
4614 "material must be 3, but got " +
4615 std::to_string(material->emissiveFactor.size()) + "\n";
4616 }
4617 return false;
4618 }
4619 } else {
4620 // fill with default values
4621 material->emissiveFactor = {0.0, 0.0, 0.0};
4622 }
4623
4624 ParseStringProperty(&material->alphaMode, err, o, "alphaMode",
4625 /* required */ false);
4626 ParseNumberProperty(&material->alphaCutoff, err, o, "alphaCutoff",
4627 /* required */ false);
4628 ParseBooleanProperty(&material->doubleSided, err, o, "doubleSided",
4629 /* required */ false);
4630
4631 {
4632 json_const_iterator it;
4633 if (FindMember(o, "pbrMetallicRoughness", it)) {
4634 ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err,
4635 GetValue(it),
4636 store_original_json_for_extras_and_extensions);
4637 }
4638 }
4639
4640 {
4641 json_const_iterator it;
4642 if (FindMember(o, "normalTexture", it)) {
4643 ParseNormalTextureInfo(&material->normalTexture, err, GetValue(it),
4644 store_original_json_for_extras_and_extensions);
4645 }
4646 }
4647
4648 {
4649 json_const_iterator it;
4650 if (FindMember(o, "occlusionTexture", it)) {
4651 ParseOcclusionTextureInfo(&material->occlusionTexture, err, GetValue(it),
4652 store_original_json_for_extras_and_extensions);
4653 }
4654 }
4655
4656 {
4657 json_const_iterator it;
4658 if (FindMember(o, "emissiveTexture", it)) {
4659 ParseTextureInfo(&material->emissiveTexture, err, GetValue(it),
4660 store_original_json_for_extras_and_extensions);
4661 }
4662 }
4663
4664 // Old code path. For backward compatibility, we still store material values
4665 // as Parameter. This will create duplicated information for
4666 // example(pbrMetallicRoughness), but should be neglible in terms of memory
4667 // consumption.
4668 // TODO(syoyo): Remove in the next major release.
33434669 material->values.clear();
3344 material->extensions.clear();
33454670 material->additionalValues.clear();
33464671
3347 json::const_iterator it(o.begin());
3348 json::const_iterator itEnd(o.end());
3349
3350 for (; it != itEnd; it++) {
3351 if (it.key() == "pbrMetallicRoughness") {
3352 if (it.value().is_object()) {
3353 const json &values_object = it.value();
3354
3355 json::const_iterator itVal(values_object.begin());
3356 json::const_iterator itValEnd(values_object.end());
3357
3358 for (; itVal != itValEnd; itVal++) {
4672 json_const_iterator it(ObjectBegin(o));
4673 json_const_iterator itEnd(ObjectEnd(o));
4674
4675 for (; it != itEnd; ++it) {
4676 std::string key(GetKey(it));
4677 if (key == "pbrMetallicRoughness") {
4678 if (IsObject(GetValue(it))) {
4679 const json &values_object = GetValue(it);
4680
4681 json_const_iterator itVal(ObjectBegin(values_object));
4682 json_const_iterator itValEnd(ObjectEnd(values_object));
4683
4684 for (; itVal != itValEnd; ++itVal) {
33594685 Parameter param;
3360 if (ParseParameterProperty(&param, err, values_object, itVal.key(),
4686 if (ParseParameterProperty(&param, err, values_object, GetKey(itVal),
33614687 false)) {
3362 material->values[itVal.key()] = param;
4688 material->values.emplace(GetKey(itVal), std::move(param));
33634689 }
33644690 }
33654691 }
3366 } else if (it.key() == "extensions" || it.key() == "extras") {
4692 } else if (key == "extensions" || key == "extras") {
33674693 // done later, skip, otherwise poorly parsed contents will be saved in the
33684694 // parametermap and serialized again later
33694695 } else {
33704696 Parameter param;
3371 if (ParseParameterProperty(&param, err, o, it.key(), false)) {
3372 material->additionalValues[it.key()] = param;
3373 }
3374 }
3375 }
3376
4697 if (ParseParameterProperty(&param, err, o, key, false)) {
4698 // names of materials have already been parsed. Putting it in this map
4699 // doesn't correctly reflext the glTF specification
4700 if (key != "name")
4701 material->additionalValues.emplace(std::move(key), std::move(param));
4702 }
4703 }
4704 }
4705
4706 material->extensions.clear();
33774707 ParseExtensionsProperty(&material->extensions, err, o);
33784708 ParseExtrasProperty(&(material->extras), o);
33794709
4710 if (store_original_json_for_extras_and_extensions) {
4711 {
4712 json_const_iterator eit;
4713 if (FindMember(o, "extensions", eit)) {
4714 material->extensions_json_string = JsonToString(GetValue(eit));
4715 }
4716 }
4717 {
4718 json_const_iterator eit;
4719 if (FindMember(o, "extras", eit)) {
4720 material->extras_json_string = JsonToString(GetValue(eit));
4721 }
4722 }
4723 }
4724
33804725 return true;
33814726 }
33824727
3383 static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
3384 const json &o) {
3385 double samplerIndex = -1.0;
3386 double targetIndex = -1.0;
3387 if (!ParseNumberProperty(&samplerIndex, err, o, "sampler", true,
3388 "AnimationChannel")) {
4728 static bool ParseAnimationChannel(
4729 AnimationChannel *channel, std::string *err, const json &o,
4730 bool store_original_json_for_extras_and_extensions) {
4731 int samplerIndex = -1;
4732 int targetIndex = -1;
4733 if (!ParseIntegerProperty(&samplerIndex, err, o, "sampler", true,
4734 "AnimationChannel")) {
33894735 if (err) {
33904736 (*err) += "`sampler` field is missing in animation channels\n";
33914737 }
33924738 return false;
33934739 }
33944740