Updated tiny gltf
assiduous
2 years ago
3 | 3 | // |
4 | 4 | // The MIT License (MIT) |
5 | 5 | // |
6 | // Copyright (c) 2015 - 2019 Syoyo Fujita, Aurélien Chatelain and many | |
6 | // Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many | |
7 | 7 | // contributors. |
8 | 8 | // |
9 | 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
25 | 25 | // THE SOFTWARE. |
26 | 26 | |
27 | 27 | // 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. | |
28 | 36 | // - v2.2.0 Add loading 16bit PNG support. Add Sparse accessor support(Thanks |
29 | 37 | // to @Ybalrid) |
30 | 38 | // - v2.1.0 Add draco compression. |
45 | 53 | #include <cstdint> |
46 | 54 | #include <cstdlib> |
47 | 55 | #include <cstring> |
56 | #include <limits> | |
48 | 57 | #include <map> |
49 | 58 | #include <string> |
50 | 59 | #include <vector> |
51 | 60 | |
61 | #ifndef TINYGLTF_USE_CPP14 | |
62 | #include <functional> | |
63 | #endif | |
64 | ||
52 | 65 | #ifdef __ANDROID__ |
53 | 66 | #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS |
54 | 67 | #include <android/asset_manager.h> |
55 | 68 | #endif |
56 | 69 | #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; | |
57 | 87 | |
58 | 88 | namespace tinygltf { |
59 | 89 | |
156 | 186 | |
157 | 187 | typedef enum { |
158 | 188 | NULL_TYPE = 0, |
159 | NUMBER_TYPE = 1, | |
189 | REAL_TYPE = 1, | |
160 | 190 | INT_TYPE = 2, |
161 | 191 | BOOL_TYPE = 3, |
162 | 192 | STRING_TYPE = 4, |
188 | 218 | } |
189 | 219 | } |
190 | 220 | |
191 | static inline int32_t GetTypeSizeInBytes(uint32_t ty) { | |
221 | static inline int32_t GetNumComponentsInType(uint32_t ty) { | |
192 | 222 | if (ty == TINYGLTF_TYPE_SCALAR) { |
193 | 223 | return 1; |
194 | 224 | } else if (ty == TINYGLTF_TYPE_VEC2) { |
209 | 239 | } |
210 | 240 | } |
211 | 241 | |
242 | // TODO(syoyo): Move these functions to TinyGLTF class | |
212 | 243 | bool IsDataURI(const std::string &in); |
213 | 244 | bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type, |
214 | 245 | const std::string &in, size_t reqBytes, bool checkSize); |
227 | 258 | typedef std::vector<Value> Array; |
228 | 259 | typedef std::map<std::string, Value> Object; |
229 | 260 | |
230 | Value() : type_(NULL_TYPE) {} | |
261 | Value() | |
262 | : type_(NULL_TYPE), | |
263 | int_value_(0), | |
264 | real_value_(0.0), | |
265 | boolean_value_(false) {} | |
231 | 266 | |
232 | 267 | 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; } | |
235 | 273 | explicit Value(const std::string &s) : type_(STRING_TYPE) { |
236 | 274 | string_value_ = s; |
237 | 275 | } |
276 | explicit Value(std::string &&s) | |
277 | : type_(STRING_TYPE), string_value_(std::move(s)) {} | |
238 | 278 | explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) { |
239 | 279 | binary_value_.resize(n); |
240 | 280 | memcpy(binary_value_.data(), p, n); |
241 | 281 | } |
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) | |
248 | 294 | |
249 | 295 | char Type() const { return static_cast<const char>(type_); } |
250 | 296 | |
252 | 298 | |
253 | 299 | bool IsInt() const { return (type_ == INT_TYPE); } |
254 | 300 | |
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); } | |
256 | 304 | |
257 | 305 | bool IsString() const { return (type_ == STRING_TYPE); } |
258 | 306 | |
261 | 309 | bool IsArray() const { return (type_ == ARRAY_TYPE); } |
262 | 310 | |
263 | 311 | 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 | } | |
264 | 330 | |
265 | 331 | // Accessor |
266 | 332 | template <typename T> |
316 | 382 | bool operator==(const tinygltf::Value &other) const; |
317 | 383 | |
318 | 384 | 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; | |
323 | 389 | std::string string_value_; |
324 | 390 | std::vector<unsigned char> binary_value_; |
325 | 391 | Array array_value_; |
326 | 392 | Object object_value_; |
327 | bool boolean_value_; | |
393 | bool boolean_value_ = false; | |
328 | 394 | }; |
329 | 395 | |
330 | 396 | #ifdef __clang__ |
341 | 407 | return var; \ |
342 | 408 | } |
343 | 409 | TINYGLTF_VALUE_GET(bool, boolean_value_) |
344 | TINYGLTF_VALUE_GET(double, number_value_) | |
410 | TINYGLTF_VALUE_GET(double, real_value_) | |
345 | 411 | TINYGLTF_VALUE_GET(int, int_value_) |
346 | 412 | TINYGLTF_VALUE_GET(std::string, string_value_) |
347 | 413 | TINYGLTF_VALUE_GET(std::vector<unsigned char>, binary_value_) |
358 | 424 | /// Agregate object for representing a color |
359 | 425 | using ColorValue = std::array<double, 4>; |
360 | 426 | |
427 | // === legacy interface ==== | |
428 | // TODO(syoyo): Deprecate `Parameter` class. | |
361 | 429 | struct Parameter { |
362 | 430 | bool bool_value = false; |
363 | 431 | bool has_number_value = false; |
365 | 433 | std::vector<double> number_array; |
366 | 434 | std::map<std::string, double> json_double_value; |
367 | 435 | double number_value = 0.0; |
436 | ||
368 | 437 | // context sensitive methods. depending the type of the Parameter you are |
369 | 438 | // accessing, these are either valid or not |
370 | 439 | // If this parameter represent a texture map in a material, will return the |
389 | 458 | if (it != std::end(json_double_value)) { |
390 | 459 | return int(it->second); |
391 | 460 | } |
461 | // As per the spec, if texCoord is ommited, this parameter is 0 | |
392 | 462 | 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; | |
393 | 487 | } |
394 | 488 | |
395 | 489 | /// Material factor, like the roughness or metalness of a material |
407 | 501 | (number_array.size() > 3 ? number_array[3] : 1.0)}}; |
408 | 502 | } |
409 | 503 | |
504 | Parameter() = default; | |
505 | DEFAULT_METHODS(Parameter) | |
410 | 506 | bool operator==(const Parameter &) const; |
411 | 507 | }; |
412 | 508 | |
428 | 524 | std::string target_path; // required in ["translation", "rotation", "scale", |
429 | 525 | // "weights"] |
430 | 526 | 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; | |
431 | 534 | |
432 | 535 | AnimationChannel() : sampler(-1), target_node(-1) {} |
536 | DEFAULT_METHODS(AnimationChannel) | |
433 | 537 | bool operator==(const AnimationChannel &) const; |
434 | 538 | }; |
435 | 539 | |
436 | 540 | struct AnimationSampler { |
437 | 541 | int input; // required |
438 | 542 | 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" | |
441 | 545 | Value extras; |
546 | ExtensionMap extensions; | |
547 | ||
548 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
549 | std::string extras_json_string; | |
550 | std::string extensions_json_string; | |
442 | 551 | |
443 | 552 | AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {} |
553 | DEFAULT_METHODS(AnimationSampler) | |
444 | 554 | bool operator==(const AnimationSampler &) const; |
445 | 555 | }; |
446 | 556 | |
449 | 559 | std::vector<AnimationChannel> channels; |
450 | 560 | std::vector<AnimationSampler> samplers; |
451 | 561 | 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) | |
453 | 570 | bool operator==(const Animation &) const; |
454 | 571 | }; |
455 | 572 | |
459 | 576 | int skeleton; // The index of the node used as a skeleton root |
460 | 577 | std::vector<int> joints; // Indices of skeleton nodes |
461 | 578 | |
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 | ||
462 | 586 | Skin() { |
463 | 587 | inverseBindMatrices = -1; |
464 | 588 | skeleton = -1; |
465 | 589 | } |
590 | DEFAULT_METHODS(Skin) | |
466 | 591 | bool operator==(const Skin &) const; |
467 | 592 | }; |
468 | 593 | |
469 | 594 | struct Sampler { |
470 | 595 | 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 | ||
480 | 612 | Value extras; |
613 | ExtensionMap extensions; | |
614 | ||
615 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
616 | std::string extras_json_string; | |
617 | std::string extensions_json_string; | |
481 | 618 | |
482 | 619 | Sampler() |
483 | : minFilter(TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR), | |
484 | magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR), | |
620 | : minFilter(-1), | |
621 | magFilter(-1), | |
485 | 622 | wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT), |
486 | 623 | wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT), |
487 | 624 | wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {} |
625 | DEFAULT_METHODS(Sampler) | |
488 | 626 | bool operator==(const Sampler &) const; |
489 | 627 | }; |
490 | 628 | |
504 | 642 | Value extras; |
505 | 643 | ExtensionMap extensions; |
506 | 644 | |
645 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
646 | std::string extras_json_string; | |
647 | std::string extensions_json_string; | |
648 | ||
507 | 649 | // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg |
508 | 650 | // compressed for "image/jpeg" mime) This feature is good if you use custom |
509 | 651 | // image loader function. (e.g. delayed decoding of images for faster glTF |
518 | 660 | height = -1; |
519 | 661 | component = -1; |
520 | 662 | } |
663 | DEFAULT_METHODS(Image) | |
664 | ||
521 | 665 | bool operator==(const Image &) const; |
522 | 666 | }; |
523 | 667 | |
529 | 673 | Value extras; |
530 | 674 | ExtensionMap extensions; |
531 | 675 | |
676 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
677 | std::string extras_json_string; | |
678 | std::string extensions_json_string; | |
679 | ||
532 | 680 | Texture() : sampler(-1), source(-1) {} |
681 | DEFAULT_METHODS(Texture) | |
682 | ||
533 | 683 | 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; | |
534 | 762 | }; |
535 | 763 | |
536 | 764 | // Each extension should be stored in a ParameterMap. |
539 | 767 | struct Material { |
540 | 768 | std::string name; |
541 | 769 | |
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; | |
544 | 785 | |
545 | 786 | ExtensionMap extensions; |
546 | 787 | Value extras; |
547 | 788 | |
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 | ||
548 | 796 | bool operator==(const Material &) const; |
549 | 797 | }; |
550 | 798 | |
551 | 799 | struct BufferView { |
552 | 800 | 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 = | |
557 | 805 | // 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 | |
559 | 807 | 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) | |
563 | 818 | bool operator==(const BufferView &) const; |
564 | 819 | }; |
565 | 820 | |
573 | 828 | size_t count; // required |
574 | 829 | int type; // (required) One of TINYGLTF_TYPE_*** .. |
575 | 830 | Value extras; |
831 | ExtensionMap extensions; | |
832 | ||
833 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
834 | std::string extras_json_string; | |
835 | std::string extensions_json_string; | |
576 | 836 | |
577 | 837 | std::vector<double> minValues; // optional |
578 | 838 | std::vector<double> maxValues; // optional |
604 | 864 | return -1; |
605 | 865 | } |
606 | 866 | |
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) { | |
609 | 869 | return -1; |
610 | 870 | } |
611 | 871 | |
612 | return componentSizeInBytes * typeSizeInBytes; | |
872 | return componentSizeInBytes * numComponents; | |
613 | 873 | } else { |
614 | 874 | // Check if byteStride is a mulple of the size of the accessor's component |
615 | 875 | // type. |
625 | 885 | return static_cast<int>(bufferViewObject.byteStride); |
626 | 886 | } |
627 | 887 | |
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){ | |
633 | 898 | sparse.isSparse = false; |
634 | 899 | } |
900 | DEFAULT_METHODS(Accessor) | |
635 | 901 | bool operator==(const tinygltf::Accessor &) const; |
636 | 902 | }; |
637 | 903 | |
647 | 913 | zfar(0.0) // 0 = use infinite projecton matrix |
648 | 914 | , |
649 | 915 | znear(0.0) {} |
916 | DEFAULT_METHODS(PerspectiveCamera) | |
650 | 917 | bool operator==(const PerspectiveCamera &) const; |
651 | 918 | |
652 | 919 | ExtensionMap extensions; |
653 | 920 | Value extras; |
921 | ||
922 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
923 | std::string extras_json_string; | |
924 | std::string extensions_json_string; | |
654 | 925 | }; |
655 | 926 | |
656 | 927 | struct OrthographicCamera { |
660 | 931 | double znear; // required |
661 | 932 | |
662 | 933 | OrthographicCamera() : xmag(0.0), ymag(0.0), zfar(0.0), znear(0.0) {} |
934 | DEFAULT_METHODS(OrthographicCamera) | |
663 | 935 | bool operator==(const OrthographicCamera &) const; |
664 | 936 | |
665 | 937 | ExtensionMap extensions; |
666 | 938 | Value extras; |
939 | ||
940 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
941 | std::string extras_json_string; | |
942 | std::string extensions_json_string; | |
667 | 943 | }; |
668 | 944 | |
669 | 945 | struct Camera { |
674 | 950 | OrthographicCamera orthographic; |
675 | 951 | |
676 | 952 | Camera() {} |
953 | DEFAULT_METHODS(Camera) | |
677 | 954 | bool operator==(const Camera &) const; |
678 | 955 | |
679 | 956 | ExtensionMap extensions; |
680 | 957 | Value extras; |
958 | ||
959 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
960 | std::string extras_json_string; | |
961 | std::string extensions_json_string; | |
681 | 962 | }; |
682 | 963 | |
683 | 964 | struct Primitive { |
696 | 977 | ExtensionMap extensions; |
697 | 978 | Value extras; |
698 | 979 | |
980 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
981 | std::string extras_json_string; | |
982 | std::string extensions_json_string; | |
983 | ||
699 | 984 | Primitive() { |
700 | 985 | material = -1; |
701 | 986 | indices = -1; |
702 | 987 | } |
988 | DEFAULT_METHODS(Primitive) | |
703 | 989 | bool operator==(const Primitive &) const; |
704 | 990 | }; |
705 | 991 | |
707 | 993 | std::string name; |
708 | 994 | std::vector<Primitive> primitives; |
709 | 995 | std::vector<double> weights; // weights to be applied to the Morph Targets |
710 | std::vector<std::map<std::string, int> > targets; | |
711 | 996 | ExtensionMap extensions; |
712 | 997 | Value extras; |
713 | 998 | |
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) | |
714 | 1005 | bool operator==(const Mesh &) const; |
715 | 1006 | }; |
716 | 1007 | |
718 | 1009 | public: |
719 | 1010 | Node() : camera(-1), skin(-1), mesh(-1) {} |
720 | 1011 | |
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 | ||
738 | 1014 | bool operator==(const Node &) const; |
739 | 1015 | |
740 | 1016 | int camera; // the index of the camera referenced by this node |
751 | 1027 | |
752 | 1028 | ExtensionMap extensions; |
753 | 1029 | Value extras; |
1030 | ||
1031 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
1032 | std::string extras_json_string; | |
1033 | std::string extensions_json_string; | |
754 | 1034 | }; |
755 | 1035 | |
756 | 1036 | struct Buffer { |
759 | 1039 | std::string |
760 | 1040 | uri; // considered as required here but not in the spec (need to clarify) |
761 | 1041 | 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) | |
763 | 1050 | bool operator==(const Buffer &) const; |
764 | 1051 | }; |
765 | 1052 | |
771 | 1058 | ExtensionMap extensions; |
772 | 1059 | Value extras; |
773 | 1060 | |
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) | |
774 | 1067 | bool operator==(const Asset &) const; |
775 | 1068 | }; |
776 | 1069 | |
781 | 1074 | ExtensionMap extensions; |
782 | 1075 | Value extras; |
783 | 1076 | |
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) | |
784 | 1083 | 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; | |
785 | 1100 | }; |
786 | 1101 | |
787 | 1102 | struct Light { |
788 | 1103 | std::string name; |
789 | 1104 | std::vector<double> color; |
1105 | double intensity; | |
790 | 1106 | std::string type; |
1107 | double range; | |
1108 | SpotLight spot; | |
1109 | ||
1110 | Light() : intensity(1.0), range(0.0) {} | |
1111 | DEFAULT_METHODS(Light) | |
791 | 1112 | |
792 | 1113 | 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; | |
793 | 1121 | }; |
794 | 1122 | |
795 | 1123 | class Model { |
796 | 1124 | public: |
797 | Model() {} | |
798 | ~Model() {} | |
1125 | Model() = default; | |
1126 | DEFAULT_METHODS(Model) | |
1127 | ||
799 | 1128 | bool operator==(const Model &) const; |
800 | 1129 | |
801 | 1130 | std::vector<Accessor> accessors; |
812 | 1141 | std::vector<Camera> cameras; |
813 | 1142 | std::vector<Scene> scenes; |
814 | 1143 | std::vector<Light> lights; |
815 | ExtensionMap extensions; | |
816 | ||
817 | int defaultScene; | |
1144 | ||
1145 | int defaultScene = -1; | |
818 | 1146 | std::vector<std::string> extensionsUsed; |
819 | 1147 | std::vector<std::string> extensionsRequired; |
820 | 1148 | |
821 | 1149 | Asset asset; |
822 | 1150 | |
823 | 1151 | Value extras; |
1152 | ExtensionMap extensions; | |
1153 | ||
1154 | // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. | |
1155 | std::string extras_json_string; | |
1156 | std::string extensions_json_string; | |
824 | 1157 | }; |
825 | 1158 | |
826 | 1159 | enum SectionCheck { |
827 | 1160 | 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 | |
835 | 1169 | }; |
836 | 1170 | |
837 | 1171 | /// |
911 | 1245 | const std::vector<unsigned char> &contents, void *); |
912 | 1246 | #endif |
913 | 1247 | |
1248 | /// | |
1249 | /// glTF Parser/Serialier context. | |
1250 | /// | |
914 | 1251 | class TinyGLTF { |
915 | 1252 | public: |
916 | 1253 | #ifdef __clang__ |
933 | 1270 | /// |
934 | 1271 | bool LoadASCIIFromFile(Model *model, std::string *err, std::string *warn, |
935 | 1272 | const std::string &filename, |
936 | unsigned int check_sections = REQUIRE_ALL); | |
1273 | unsigned int check_sections = REQUIRE_VERSION); | |
937 | 1274 | |
938 | 1275 | /// |
939 | 1276 | /// Loads glTF ASCII asset from string(memory). |
944 | 1281 | bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn, |
945 | 1282 | const char *str, const unsigned int length, |
946 | 1283 | const std::string &base_dir, |
947 | unsigned int check_sections = REQUIRE_ALL); | |
1284 | unsigned int check_sections = REQUIRE_VERSION); | |
948 | 1285 | |
949 | 1286 | /// |
950 | 1287 | /// Loads glTF binary asset from a file. |
953 | 1290 | /// |
954 | 1291 | bool LoadBinaryFromFile(Model *model, std::string *err, std::string *warn, |
955 | 1292 | const std::string &filename, |
956 | unsigned int check_sections = REQUIRE_ALL); | |
1293 | unsigned int check_sections = REQUIRE_VERSION); | |
957 | 1294 | |
958 | 1295 | /// |
959 | 1296 | /// Loads glTF binary asset from memory. |
965 | 1302 | const unsigned char *bytes, |
966 | 1303 | const unsigned int length, |
967 | 1304 | 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); | |
969 | 1312 | |
970 | 1313 | /// |
971 | 1314 | /// Write glTF to file. |
988 | 1331 | /// Set callbacks to use for filesystem (fs) access and their user data |
989 | 1332 | /// |
990 | 1333 | 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 | } | |
991 | 1362 | |
992 | 1363 | private: |
993 | 1364 | /// |
1000 | 1371 | const char *str, const unsigned int length, |
1001 | 1372 | const std::string &base_dir, unsigned int check_sections); |
1002 | 1373 | |
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; | |
1006 | 1381 | |
1007 | 1382 | FsCallbacks fs = { |
1008 | 1383 | #ifndef TINYGLTF_NO_FS |
1046 | 1421 | #include <algorithm> |
1047 | 1422 | //#include <cassert> |
1048 | 1423 | #ifndef TINYGLTF_NO_FS |
1424 | #include <cstdio> | |
1049 | 1425 | #include <fstream> |
1050 | 1426 | #endif |
1051 | 1427 | #include <sstream> |
1058 | 1434 | #pragma clang diagnostic ignored "-Wconversion" |
1059 | 1435 | #pragma clang diagnostic ignored "-Wold-style-cast" |
1060 | 1436 | #pragma clang diagnostic ignored "-Wglobal-constructors" |
1437 | #if __has_warning("-Wreserved-id-macro") | |
1061 | 1438 | #pragma clang diagnostic ignored "-Wreserved-id-macro" |
1439 | #endif | |
1062 | 1440 | #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" |
1063 | 1441 | #pragma clang diagnostic ignored "-Wpadded" |
1064 | 1442 | #pragma clang diagnostic ignored "-Wc++98-compat" |
1098 | 1476 | #if __has_warning("-Wmismatched-tags") |
1099 | 1477 | #pragma clang diagnostic ignored "-Wmismatched-tags" |
1100 | 1478 | #endif |
1479 | #if __has_warning("-Wextra-semi-stmt") | |
1480 | #pragma clang diagnostic ignored "-Wextra-semi-stmt" | |
1481 | #endif | |
1101 | 1482 | #endif |
1102 | 1483 | |
1103 | 1484 | // Disable GCC warnigs |
1107 | 1488 | #endif // __GNUC__ |
1108 | 1489 | |
1109 | 1490 | #ifndef TINYGLTF_NO_INCLUDE_JSON |
1491 | #ifndef TINYGLTF_USE_RAPIDJSON | |
1110 | 1492 | #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 | |
1111 | 1500 | #endif |
1112 | 1501 | |
1113 | 1502 | #ifdef TINYGLTF_ENABLE_DRACO |
1159 | 1548 | #undef NOMINMAX |
1160 | 1549 | #endif |
1161 | 1550 | |
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 | ||
1162 | 1558 | #elif !defined(__ANDROID__) |
1163 | 1559 | #include <wordexp.h> |
1164 | 1560 | #endif |
1171 | 1567 | #endif |
1172 | 1568 | #endif |
1173 | 1569 | |
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 | |
1174 | 1634 | 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 | |
1175 | 1650 | |
1176 | 1651 | #ifdef __APPLE__ |
1177 | 1652 | #include "TargetConditionals.h" |
1193 | 1668 | return true; |
1194 | 1669 | case BOOL_TYPE: |
1195 | 1670 | return one.Get<bool>() == other.Get<bool>(); |
1196 | case NUMBER_TYPE: | |
1671 | case REAL_TYPE: | |
1197 | 1672 | return TINYGLTF_DOUBLE_EQUAL(one.Get<double>(), other.Get<double>()); |
1198 | 1673 | case INT_TYPE: |
1199 | 1674 | return one.Get<int>() == other.Get<int>(); |
1241 | 1716 | return this->bufferView == other.bufferView && |
1242 | 1717 | this->byteOffset == other.byteOffset && |
1243 | 1718 | 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 && | |
1245 | 1721 | Equals(this->maxValues, other.maxValues) && |
1246 | 1722 | Equals(this->minValues, other.minValues) && this->name == other.name && |
1247 | 1723 | this->normalized == other.normalized && this->type == other.type; |
1248 | 1724 | } |
1249 | 1725 | 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 && | |
1251 | 1728 | this->name == other.name && this->samplers == other.samplers; |
1252 | 1729 | } |
1253 | 1730 | bool AnimationChannel::operator==(const AnimationChannel &other) const { |
1254 | return this->extras == other.extras && | |
1731 | return this->extensions == other.extensions && this->extras == other.extras && | |
1255 | 1732 | this->target_node == other.target_node && |
1256 | 1733 | this->target_path == other.target_path && |
1257 | 1734 | this->sampler == other.sampler; |
1258 | 1735 | } |
1259 | 1736 | 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 && | |
1261 | 1739 | this->interpolation == other.interpolation && |
1262 | 1740 | this->output == other.output; |
1263 | 1741 | } |
1268 | 1746 | this->minVersion == other.minVersion && this->version == other.version; |
1269 | 1747 | } |
1270 | 1748 | 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; | |
1273 | 1752 | } |
1274 | 1753 | bool BufferView::operator==(const BufferView &other) const { |
1275 | 1754 | return this->buffer == other.buffer && this->byteLength == other.byteLength && |
1276 | 1755 | this->byteOffset == other.byteOffset && |
1277 | 1756 | 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 && | |
1279 | 1759 | this->dracoDecoded == other.dracoDecoded; |
1280 | 1760 | } |
1281 | 1761 | bool Camera::operator==(const Camera &other) const { |
1286 | 1766 | } |
1287 | 1767 | bool Image::operator==(const Image &other) const { |
1288 | 1768 | 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 && | |
1290 | 1771 | this->height == other.height && this->image == other.image && |
1291 | 1772 | this->mimeType == other.mimeType && this->name == other.name && |
1292 | 1773 | this->uri == other.uri && this->width == other.width; |
1296 | 1777 | this->type == other.type; |
1297 | 1778 | } |
1298 | 1779 | 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); | |
1302 | 1792 | } |
1303 | 1793 | bool Mesh::operator==(const Mesh &other) const { |
1304 | 1794 | 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; | |
1307 | 1797 | } |
1308 | 1798 | bool Model::operator==(const Model &other) const { |
1309 | 1799 | return this->accessors == other.accessors && |
1330 | 1820 | Equals(this->translation, other.translation) && |
1331 | 1821 | Equals(this->weights, other.weights); |
1332 | 1822 | } |
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 | } | |
1333 | 1828 | bool OrthographicCamera::operator==(const OrthographicCamera &other) const { |
1334 | 1829 | return this->extensions == other.extensions && this->extras == other.extras && |
1335 | 1830 | TINYGLTF_DOUBLE_EQUAL(this->xmag, other.xmag) && |
1373 | 1868 | this->mode == other.mode && this->targets == other.targets; |
1374 | 1869 | } |
1375 | 1870 | 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 && | |
1377 | 1873 | this->minFilter == other.minFilter && this->name == other.name && |
1378 | 1874 | this->wrapR == other.wrapR && this->wrapS == other.wrapS && |
1379 | 1875 | this->wrapT == other.wrapT; |
1381 | 1877 | bool Scene::operator==(const Scene &other) const { |
1382 | 1878 | return this->extensions == other.extensions && this->extras == other.extras && |
1383 | 1879 | this->name == other.name && this->nodes == other.nodes; |
1384 | ; | |
1385 | 1880 | } |
1386 | 1881 | 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 && | |
1388 | 1884 | this->joints == other.joints && this->name == other.name && |
1389 | 1885 | this->skeleton == other.skeleton; |
1390 | 1886 | } |
1392 | 1888 | return this->extensions == other.extensions && this->extras == other.extras && |
1393 | 1889 | this->name == other.name && this->sampler == other.sampler && |
1394 | 1890 | 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); | |
1395 | 1913 | } |
1396 | 1914 | bool Value::operator==(const Value &other) const { |
1397 | 1915 | return Equals(*this, other); |
1495 | 2013 | |
1496 | 2014 | #ifdef __clang__ |
1497 | 2015 | #pragma clang diagnostic push |
1498 | #pragma clang diagnostic ignored "-Wexit-time-destructors" | |
1499 | #pragma clang diagnostic ignored "-Wglobal-constructors" | |
1500 | 2016 | #pragma clang diagnostic ignored "-Wsign-conversion" |
1501 | 2017 | #pragma clang diagnostic ignored "-Wconversion" |
1502 | 2018 | #endif |
1503 | static const std::string base64_chars = | |
1504 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
1505 | "abcdefghijklmnopqrstuvwxyz" | |
1506 | "0123456789+/"; | |
1507 | 2019 | |
1508 | 2020 | static inline bool is_base64(unsigned char c) { |
1509 | 2021 | return (isalnum(c) || (c == '+') || (c == '/')); |
1516 | 2028 | int j = 0; |
1517 | 2029 | unsigned char char_array_3[3]; |
1518 | 2030 | unsigned char char_array_4[4]; |
2031 | ||
2032 | const char *base64_chars = | |
2033 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
2034 | "abcdefghijklmnopqrstuvwxyz" | |
2035 | "0123456789+/"; | |
1519 | 2036 | |
1520 | 2037 | while (in_len--) { |
1521 | 2038 | char_array_3[i++] = *(bytes_to_encode++); |
1556 | 2073 | int in_ = 0; |
1557 | 2074 | unsigned char char_array_4[4], char_array_3[3]; |
1558 | 2075 | std::string ret; |
2076 | ||
2077 | const std::string base64_chars = | |
2078 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
2079 | "abcdefghijklmnopqrstuvwxyz" | |
2080 | "0123456789+/"; | |
1559 | 2081 | |
1560 | 2082 | while (in_len-- && (encoded_string[in_] != '=') && |
1561 | 2083 | is_base64(encoded_string[in_])) { |
1678 | 2200 | (void)user_data; |
1679 | 2201 | (void)warn; |
1680 | 2202 | |
1681 | int w, h, comp, req_comp; | |
2203 | int w = 0, h = 0, comp = 0, req_comp = 0; | |
1682 | 2204 | |
1683 | 2205 | unsigned char *data = nullptr; |
1684 | 2206 | |
1695 | 2217 | // the Image metadata to signal that this image uses 2 bytes (16bits) per |
1696 | 2218 | // channel: |
1697 | 2219 | 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)); | |
1700 | 2222 | if (data) { |
1701 | 2223 | bits = 16; |
1702 | 2224 | pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; |
1723 | 2245 | return false; |
1724 | 2246 | } |
1725 | 2247 | |
1726 | if (w < 1 || h < 1) { | |
2248 | if ((w < 1) || (h < 1)) { | |
1727 | 2249 | stbi_image_free(data); |
1728 | 2250 | if (err) { |
1729 | 2251 | (*err) += "Invalid image data for image[" + std::to_string(image_idx) + |
1761 | 2283 | image->component = req_comp; |
1762 | 2284 | image->bits = bits; |
1763 | 2285 | 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)); | |
1765 | 2287 | std::copy(data, data + w * h * req_comp * (bits / 8), image->image.begin()); |
1766 | 2288 | stbi_image_free(data); |
1767 | 2289 | |
1856 | 2378 | |
1857 | 2379 | void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; } |
1858 | 2380 | |
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 | ||
1859 | 2390 | #ifndef TINYGLTF_NO_FS |
1860 | 2391 | // Default implementations of filesystem functions |
1861 | 2392 | |
1875 | 2406 | } |
1876 | 2407 | #else |
1877 | 2408 | #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; | |
1879 | 2417 | errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb"); |
1880 | 2418 | if (err != 0) { |
1881 | 2419 | return false; |
1882 | 2420 | } |
2421 | #endif | |
2422 | ||
1883 | 2423 | #else |
1884 | 2424 | FILE *fp = fopen(abs_filename.c_str(), "rb"); |
1885 | 2425 | #endif |
1919 | 2459 | return ""; |
1920 | 2460 | } |
1921 | 2461 | |
2462 | // Quote the string to keep any spaces in filepath intact. | |
2463 | std::string quoted_path = "\"" + filepath + "\""; | |
1922 | 2464 | // char** w; |
1923 | int ret = wordexp(filepath.c_str(), &p, 0); | |
2465 | int ret = wordexp(quoted_path.c_str(), &p, 0); | |
1924 | 2466 | if (ret) { |
1925 | 2467 | // err |
1926 | 2468 | s = filepath; |
1971 | 2513 | return false; |
1972 | 2514 | } |
1973 | 2515 | #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? | |
1974 | 2524 | 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 | |
1975 | 2529 | if (!f) { |
1976 | 2530 | if (err) { |
1977 | 2531 | (*err) += "File open error : " + filepath + "\n"; |
1983 | 2537 | size_t sz = static_cast<size_t>(f.tellg()); |
1984 | 2538 | f.seekg(0, f.beg); |
1985 | 2539 | |
1986 | if (int(sz) < 0) { | |
2540 | if (int64_t(sz) < 0) { | |
1987 | 2541 | if (err) { |
1988 | 2542 | (*err) += "Invalid file size : " + filepath + |
1989 | 2543 | " (does the path point to a directory?)"; |
1999 | 2553 | out->resize(sz); |
2000 | 2554 | f.read(reinterpret_cast<char *>(&out->at(0)), |
2001 | 2555 | static_cast<std::streamsize>(sz)); |
2002 | f.close(); | |
2003 | 2556 | |
2004 | 2557 | return true; |
2005 | 2558 | #endif |
2007 | 2560 | |
2008 | 2561 | bool WriteWholeFile(std::string *err, const std::string &filepath, |
2009 | 2562 | 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? | |
2010 | 2571 | 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 | |
2011 | 2576 | if (!f) { |
2012 | 2577 | if (err) { |
2013 | 2578 | (*err) += "File open error for writing : " + filepath + "\n"; |
2024 | 2589 | return false; |
2025 | 2590 | } |
2026 | 2591 | |
2027 | f.close(); | |
2028 | 2592 | return true; |
2029 | 2593 | } |
2030 | 2594 | |
2167 | 2731 | } |
2168 | 2732 | } |
2169 | 2733 | |
2734 | // TODO(syoyo): Allow empty buffer? #229 | |
2170 | 2735 | if (data.empty()) { |
2171 | 2736 | return false; |
2172 | 2737 | } |
2183 | 2748 | return true; |
2184 | 2749 | } |
2185 | 2750 | |
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 | ||
2186 | 2928 | static bool ParseJsonAsValue(Value *ret, const json &o) { |
2187 | 2929 | 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 | |
2188 | 2977 | switch (o.type()) { |
2189 | 2978 | case json::value_t::object: { |
2190 | 2979 | Value::Object value_object; |
2191 | 2980 | for (auto it = o.begin(); it != o.end(); it++) { |
2192 | 2981 | Value entry; |
2193 | 2982 | 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)); | |
2197 | 2987 | } break; |
2198 | 2988 | case json::value_t::array: { |
2199 | 2989 | Value::Array value_array; |
2990 | value_array.reserve(o.size()); | |
2200 | 2991 | for (auto it = o.begin(); it != o.end(); it++) { |
2201 | 2992 | Value entry; |
2202 | 2993 | 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)); | |
2206 | 2998 | } break; |
2207 | 2999 | case json::value_t::string: |
2208 | 3000 | val = Value(o.get<std::string>()); |
2222 | 3014 | // default: |
2223 | 3015 | break; |
2224 | 3016 | } |
2225 | if (ret) *ret = val; | |
3017 | #endif | |
3018 | if (ret) *ret = std::move(val); | |
2226 | 3019 | |
2227 | 3020 | return val.Type() != NULL_TYPE; |
2228 | 3021 | } |
2229 | 3022 | |
2230 | 3023 | 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)); | |
2237 | 3030 | } |
2238 | 3031 | |
2239 | 3032 | static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o, |
2240 | 3033 | const std::string &property, |
2241 | 3034 | const bool required, |
2242 | 3035 | 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)) { | |
2245 | 3038 | if (required) { |
2246 | 3039 | if (err) { |
2247 | 3040 | (*err) += "'" + property + "' property is missing"; |
2254 | 3047 | return false; |
2255 | 3048 | } |
2256 | 3049 | |
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) { | |
2258 | 3066 | if (required) { |
2259 | 3067 | if (err) { |
2260 | 3068 | (*err) += "'" + property + "' property is not a bool type.\n"; |
2264 | 3072 | } |
2265 | 3073 | |
2266 | 3074 | if (ret) { |
2267 | (*ret) = it.value().get<bool>(); | |
3075 | (*ret) = boolValue; | |
2268 | 3076 | } |
2269 | 3077 | |
2270 | 3078 | return true; |
2271 | 3079 | } |
2272 | 3080 | |
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)) { | |
2279 | 3087 | if (required) { |
2280 | 3088 | if (err) { |
2281 | 3089 | (*err) += "'" + property + "' property is missing"; |
2288 | 3096 | return false; |
2289 | 3097 | } |
2290 | 3098 | |
2291 | if (!it.value().is_number()) { | |
3099 | int intValue; | |
3100 | bool isInt = GetInt(GetValue(it), intValue); | |
3101 | if (!isInt) { | |
2292 | 3102 | if (required) { |
2293 | 3103 | if (err) { |
2294 | (*err) += "'" + property + "' property is not a number type.\n"; | |
3104 | (*err) += "'" + property + "' property is not an integer type.\n"; | |
2295 | 3105 | } |
2296 | 3106 | } |
2297 | 3107 | return false; |
2298 | 3108 | } |
2299 | 3109 | |
2300 | 3110 | if (ret) { |
2301 | (*ret) = it.value().get<double>(); | |
3111 | (*ret) = intValue; | |
2302 | 3112 | } |
2303 | 3113 | |
2304 | 3114 | return true; |
2305 | 3115 | } |
2306 | 3116 | |
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)) { | |
2313 | 3123 | if (required) { |
2314 | 3124 | if (err) { |
2315 | 3125 | (*err) += "'" + property + "' property is missing"; |
2322 | 3132 | return false; |
2323 | 3133 | } |
2324 | 3134 | |
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))) { | |
2326 | 3227 | if (required) { |
2327 | 3228 | if (err) { |
2328 | 3229 | (*err) += "'" + property + "' property is not an array"; |
2336 | 3237 | } |
2337 | 3238 | |
2338 | 3239 | 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) { | |
2342 | 3245 | if (required) { |
2343 | 3246 | if (err) { |
2344 | 3247 | (*err) += "'" + property + "' property is not a number.\n"; |
2350 | 3253 | } |
2351 | 3254 | return false; |
2352 | 3255 | } |
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); | |
2354 | 3312 | } |
2355 | 3313 | |
2356 | 3314 | return true; |
2360 | 3318 | std::string *ret, std::string *err, const json &o, |
2361 | 3319 | const std::string &property, bool required, |
2362 | 3320 | 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)) { | |
2365 | 3323 | if (required) { |
2366 | 3324 | if (err) { |
2367 | 3325 | (*err) += "'" + property + "' property is missing"; |
2375 | 3333 | return false; |
2376 | 3334 | } |
2377 | 3335 | |
2378 | if (!it.value().is_string()) { | |
3336 | std::string strValue; | |
3337 | if (!GetString(GetValue(it), strValue)) { | |
2379 | 3338 | if (required) { |
2380 | 3339 | if (err) { |
2381 | 3340 | (*err) += "'" + property + "' property is not a string type.\n"; |
2385 | 3344 | } |
2386 | 3345 | |
2387 | 3346 | if (ret) { |
2388 | (*ret) = it.value().get<std::string>(); | |
3347 | (*ret) = std::move(strValue); | |
2389 | 3348 | } |
2390 | 3349 | |
2391 | 3350 | return true; |
2392 | 3351 | } |
2393 | 3352 | |
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)) { | |
2400 | 3360 | if (required) { |
2401 | 3361 | if (err) { |
2402 | 3362 | if (!parent.empty()) { |
2410 | 3370 | return false; |
2411 | 3371 | } |
2412 | 3372 | |
3373 | const json &dict = GetValue(it); | |
3374 | ||
2413 | 3375 | // Make sure we are dealing with an object / dictionary. |
2414 | if (!it.value().is_object()) { | |
3376 | if (!IsObject(dict)) { | |
2415 | 3377 | if (required) { |
2416 | 3378 | if (err) { |
2417 | 3379 | (*err) += "'" + property + "' property is not an object.\n"; |
2421 | 3383 | } |
2422 | 3384 | |
2423 | 3385 | 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)); | |
2428 | 3389 | |
2429 | 3390 | for (; dictIt != dictItEnd; ++dictIt) { |
2430 | if (!dictIt.value().is_number()) { | |
3391 | int intVal; | |
3392 | if (!GetInt(GetValue(dictIt), intVal)) { | |
2431 | 3393 | if (required) { |
2432 | 3394 | if (err) { |
2433 | (*err) += "'" + property + "' value is not an int.\n"; | |
3395 | (*err) += "'" + property + "' value is not an integer type.\n"; | |
2434 | 3396 | } |
2435 | 3397 | } |
2436 | 3398 | return false; |
2437 | 3399 | } |
2438 | 3400 | |
2439 | 3401 | // Insert into the list. |
2440 | (*ret)[dictIt.key()] = static_cast<int>(dictIt.value()); | |
3402 | (*ret)[GetKey(dictIt)] = intVal; | |
2441 | 3403 | } |
2442 | 3404 | return true; |
2443 | 3405 | } |
2445 | 3407 | static bool ParseJSONProperty(std::map<std::string, double> *ret, |
2446 | 3408 | std::string *err, const json &o, |
2447 | 3409 | 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)) { | |
2450 | 3412 | if (required) { |
2451 | 3413 | if (err) { |
2452 | 3414 | (*err) += "'" + property + "' property is missing. \n'"; |
2455 | 3417 | return false; |
2456 | 3418 | } |
2457 | 3419 | |
2458 | if (!it.value().is_object()) { | |
3420 | const json &obj = GetValue(it); | |
3421 | ||
3422 | if (!IsObject(obj)) { | |
2459 | 3423 | if (required) { |
2460 | 3424 | if (err) { |
2461 | 3425 | (*err) += "'" + property + "' property is not a JSON object.\n"; |
2465 | 3429 | } |
2466 | 3430 | |
2467 | 3431 | 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); | |
2474 | 3439 | } |
2475 | 3440 | |
2476 | 3441 | return true; |
2512 | 3477 | const json &o) { |
2513 | 3478 | (void)err; |
2514 | 3479 | |
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)) { | |
2520 | 3487 | return false; |
2521 | 3488 | } |
2522 | 3489 | 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()) { | |
2528 | 3498 | // create empty object so that an extension object is still of type |
2529 | 3499 | // object |
2530 | extensions[extIt.key()] = Value{Value::Object{}}; | |
3500 | extensions[key] = Value{Value::Object{}}; | |
2531 | 3501 | } |
2532 | 3502 | } |
2533 | 3503 | } |
2534 | 3504 | if (ret) { |
2535 | (*ret) = extensions; | |
3505 | (*ret) = std::move(extensions); | |
2536 | 3506 | } |
2537 | 3507 | return true; |
2538 | 3508 | } |
2539 | 3509 | |
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) { | |
2541 | 3512 | ParseStringProperty(&asset->version, err, o, "version", true, "Asset"); |
2542 | 3513 | ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset"); |
2543 | 3514 | ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset"); |
3515 | ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset"); | |
2544 | 3516 | |
2545 | 3517 | ParseExtensionsProperty(&asset->extensions, err, o); |
2546 | 3518 | |
2547 | 3519 | // Unity exporter version is added as extra here |
2548 | 3520 | ParseExtrasProperty(&(asset->extras), o); |
2549 | 3521 | |
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 | ||
2550 | 3537 | return true; |
2551 | 3538 | } |
2552 | 3539 | |
2553 | 3540 | static bool ParseImage(Image *image, const int image_idx, std::string *err, |
2554 | 3541 | std::string *warn, const json &o, |
3542 | bool store_original_json_for_extras_and_extensions, | |
2555 | 3543 | const std::string &basedir, FsCallbacks *fs, |
2556 | 3544 | LoadImageDataFunction *LoadImageData = nullptr, |
2557 | 3545 | void *load_image_user_data = nullptr) { |
2559 | 3547 | |
2560 | 3548 | // schema says oneOf [`bufferView`, `uri`] |
2561 | 3549 | // 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); | |
2564 | 3553 | |
2565 | 3554 | ParseStringProperty(&image->name, err, o, "name", false); |
2566 | 3555 | |
2587 | 3576 | ParseExtensionsProperty(&image->extensions, err, o); |
2588 | 3577 | ParseExtrasProperty(&image->extras, o); |
2589 | 3578 | |
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 | ||
2590 | 3594 | 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)) { | |
2593 | 3597 | if (err) { |
2594 | 3598 | (*err) += "Failed to parse `bufferView` for image[" + |
2595 | 3599 | std::to_string(image_idx) + "] name = \"" + image->name + |
2601 | 3605 | std::string mime_type; |
2602 | 3606 | ParseStringProperty(&mime_type, err, o, "mimeType", false); |
2603 | 3607 | |
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); | |
2609 | 3613 | |
2610 | 3614 | // Just only save some information here. Loading actual image data from |
2611 | 3615 | // bufferView is done after this `ParseImage` function. |
2612 | image->bufferView = static_cast<int>(bufferView); | |
3616 | image->bufferView = bufferView; | |
2613 | 3617 | 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; | |
2616 | 3620 | |
2617 | 3621 | return true; |
2618 | 3622 | } |
2678 | 3682 | } |
2679 | 3683 | |
2680 | 3684 | static bool ParseTexture(Texture *texture, std::string *err, const json &o, |
3685 | bool store_original_json_for_extras_and_extensions, | |
2681 | 3686 | const std::string &basedir) { |
2682 | 3687 | (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; | |
2691 | 3696 | |
2692 | 3697 | ParseExtensionsProperty(&texture->extensions, err, o); |
2693 | 3698 | ParseExtrasProperty(&texture->extras, o); |
2694 | 3699 | |
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 | ||
2695 | 3715 | ParseStringProperty(&texture->name, err, o, "name", false); |
2696 | 3716 | |
2697 | 3717 | return true; |
2698 | 3718 | } |
2699 | 3719 | |
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 | ||
2700 | 3827 | static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, |
3828 | bool store_original_json_for_extras_and_extensions, | |
2701 | 3829 | FsCallbacks *fs, const std::string &basedir, |
2702 | 3830 | bool is_binary = false, |
2703 | 3831 | const unsigned char *bin_data = nullptr, |
2704 | 3832 | 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")) { | |
2707 | 3836 | return false; |
2708 | 3837 | } |
2709 | 3838 | |
2718 | 3847 | } |
2719 | 3848 | } |
2720 | 3849 | |
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) { | |
2726 | 3855 | // buffer.type = "arraybuffer"; |
2727 | 3856 | } |
2728 | 3857 | } |
2729 | 3858 | } |
2730 | 3859 | |
2731 | size_t bytes = static_cast<size_t>(byteLength); | |
2732 | 3860 | if (is_binary) { |
2733 | 3861 | // Still binary glTF accepts external dataURI. |
2734 | 3862 | if (!buffer->uri.empty()) { |
2735 | 3863 | // First try embedded data URI. |
2736 | 3864 | if (IsDataURI(buffer->uri)) { |
2737 | 3865 | std::string mime_type; |
2738 | if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes, | |
3866 | if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength, | |
2739 | 3867 | true)) { |
2740 | 3868 | if (err) { |
2741 | 3869 | (*err) += |
2746 | 3874 | } else { |
2747 | 3875 | // External .bin file. |
2748 | 3876 | if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, |
2749 | buffer->uri, basedir, true, bytes, true, fs)) { | |
3877 | buffer->uri, basedir, true, byteLength, true, | |
3878 | fs)) { | |
2750 | 3879 | return false; |
2751 | 3880 | } |
2752 | 3881 | } |
2779 | 3908 | } else { |
2780 | 3909 | if (IsDataURI(buffer->uri)) { |
2781 | 3910 | 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)) { | |
2783 | 3913 | if (err) { |
2784 | 3914 | (*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n"; |
2785 | 3915 | } |
2788 | 3918 | } else { |
2789 | 3919 | // Assume external .bin file. |
2790 | 3920 | if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri, |
2791 | basedir, true, bytes, true, fs)) { | |
3921 | basedir, true, byteLength, true, fs)) { | |
2792 | 3922 | return false; |
2793 | 3923 | } |
2794 | 3924 | } |
2796 | 3926 | |
2797 | 3927 | ParseStringProperty(&buffer->name, err, o, "name", false); |
2798 | 3928 | |
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 | ||
2799 | 3947 | return true; |
2800 | 3948 | } |
2801 | 3949 | |
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")) { | |
2815 | 3964 | return false; |
2816 | 3965 | } |
2817 | 3966 | |
2818 | 3967 | 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)) { | |
2821 | 3969 | // Spec says: When byteStride of referenced bufferView is not defined, it |
2822 | 3970 | // means that accessor elements are tightly packed, i.e., effective stride |
2823 | 3971 | // equals the size of the element. |
2824 | 3972 | // We cannot determine the actual byteStride until Accessor are parsed, thus |
2825 | 3973 | // set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner) |
2826 | 3974 | byteStride = 0; |
2827 | } else { | |
2828 | byteStride = static_cast<size_t>(byteStrideValue); | |
2829 | 3975 | } |
2830 | 3976 | |
2831 | 3977 | if ((byteStride > 252) || ((byteStride % 4) != 0)) { |
2840 | 3986 | return false; |
2841 | 3987 | } |
2842 | 3988 | |
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)) { | |
2848 | 3993 | // OK |
2849 | 3994 | } else { |
2850 | targetValue = 0; | |
2851 | } | |
2852 | bufferView->target = targetValue; | |
3995 | target = 0; | |
3996 | } | |
3997 | bufferView->target = target; | |
2853 | 3998 | |
2854 | 3999 | ParseStringProperty(&bufferView->name, err, o, "name", false); |
2855 | 4000 | |
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; | |
2860 | 4023 | return true; |
2861 | 4024 | } |
2862 | 4025 | |
2864 | 4027 | const json &o) { |
2865 | 4028 | accessor->sparse.isSparse = true; |
2866 | 4029 | |
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)) { | |
2873 | 4036 | (*err) = "the sparse object of this accessor doesn't have indices"; |
2874 | 4037 | return false; |
2875 | 4038 | } |
2876 | 4039 | |
2877 | if (values_iterator == o.end()) { | |
4040 | if (!FindMember(o, "values", values_iterator)) { | |
2878 | 4041 | (*err) = "the sparse object ob ths accessor doesn't have values"; |
2879 | 4042 | return false; |
2880 | 4043 | } |
2881 | 4044 | |
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; | |
2903 | 4068 | |
2904 | 4069 | // todo check theses values |
2905 | 4070 | |
2906 | 4071 | return true; |
2907 | 4072 | } |
2908 | 4073 | |
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"); | |
2915 | 4081 | |
2916 | 4082 | bool normalized = false; |
2917 | 4083 | ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor"); |
2918 | 4084 | |
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")) { | |
2927 | 4093 | return false; |
2928 | 4094 | } |
2929 | 4095 | |
2965 | 4131 | ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false, |
2966 | 4132 | "Accessor"); |
2967 | 4133 | |
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; | |
2971 | 4137 | accessor->normalized = normalized; |
2972 | 4138 | { |
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) { | |
2976 | 4141 | // OK |
2977 | accessor->componentType = comp; | |
4142 | accessor->componentType = int(componentType); | |
2978 | 4143 | } else { |
2979 | 4144 | std::stringstream ss; |
2980 | ss << "Invalid `componentType` in accessor. Got " << comp << "\n"; | |
4145 | ss << "Invalid `componentType` in accessor. Got " << componentType | |
4146 | << "\n"; | |
2981 | 4147 | if (err) { |
2982 | 4148 | (*err) += ss.str(); |
2983 | 4149 | } |
2985 | 4151 | } |
2986 | 4152 | } |
2987 | 4153 | |
4154 | ParseExtensionsProperty(&(accessor->extensions), err, o); | |
2988 | 4155 | ParseExtrasProperty(&(accessor->extras), o); |
2989 | 4156 | |
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 | ||
2990 | 4172 | // 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)) { | |
2993 | 4175 | // here this accessor has a "sparse" subobject |
2994 | return ParseSparseAccessor(accessor, err, *iterator); | |
4176 | return ParseSparseAccessor(accessor, err, GetValue(iterator)); | |
2995 | 4177 | } |
2996 | 4178 | |
2997 | 4179 | return true; |
3190 | 4372 | #endif |
3191 | 4373 | |
3192 | 4374 | 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")) { | |
3209 | 4390 | return false; |
3210 | 4391 | } |
3211 | 4392 | |
3212 | 4393 | // 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) { | |
3217 | 4400 | std::map<std::string, int> targetAttribues; |
3218 | 4401 | |
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 | } | |
3227 | 4414 | } |
3228 | 4415 | } |
3229 | 4416 | |
3230 | 4417 | ParseExtrasProperty(&(primitive->extras), o); |
3231 | ||
3232 | 4418 | 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 | } | |
3233 | 4434 | |
3234 | 4435 | #ifdef TINYGLTF_ENABLE_DRACO |
3235 | 4436 | auto dracoExtension = |
3244 | 4445 | return true; |
3245 | 4446 | } |
3246 | 4447 | |
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) { | |
3249 | 4450 | ParseStringProperty(&mesh->name, err, o, "name", false); |
3250 | 4451 | |
3251 | 4452 | 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) { | |
3256 | 4459 | 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)) { | |
3258 | 4462 | // 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 | } | |
3279 | 4465 | } |
3280 | 4466 | } |
3281 | 4467 | |
3285 | 4471 | ParseExtensionsProperty(&mesh->extensions, err, o); |
3286 | 4472 | ParseExtrasProperty(&(mesh->extras), o); |
3287 | 4473 | |
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 | ||
3288 | 4489 | return true; |
3289 | 4490 | } |
3290 | 4491 | |
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) { | |
3299 | 4494 | ParseStringProperty(&node->name, err, o, "name", false); |
3300 | 4495 | |
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; | |
3304 | 4499 | |
3305 | 4500 | // Matrix and T/R/S are exclusive |
3306 | 4501 | if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) { |
3309 | 4504 | ParseNumberArrayProperty(&node->translation, err, o, "translation", false); |
3310 | 4505 | } |
3311 | 4506 | |
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; | |
3319 | 4514 | |
3320 | 4515 | 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); | |
3335 | 4519 | |
3336 | 4520 | ParseExtensionsProperty(&node->extensions, err, o); |
3337 | 4521 | ParseExtrasProperty(&(node->extras), o); |
3338 | 4522 | |
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 | ||
3339 | 4538 | return true; |
3340 | 4539 | } |
3341 | 4540 | |
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. | |
3343 | 4669 | material->values.clear(); |
3344 | material->extensions.clear(); | |
3345 | 4670 | material->additionalValues.clear(); |
3346 | 4671 | |
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) { | |
3359 | 4685 | Parameter param; |
3360 | if (ParseParameterProperty(¶m, err, values_object, itVal.key(), | |
4686 | if (ParseParameterProperty(¶m, err, values_object, GetKey(itVal), | |
3361 | 4687 | false)) { |
3362 | material->values[itVal.key()] = param; | |
4688 | material->values.emplace(GetKey(itVal), std::move(param)); | |
3363 | 4689 | } |
3364 | 4690 | } |
3365 | 4691 | } |
3366 | } else if (it.key() == "extensions" || it.key() == "extras") { | |
4692 | } else if (key == "extensions" || key == "extras") { | |
3367 | 4693 | // done later, skip, otherwise poorly parsed contents will be saved in the |
3368 | 4694 | // parametermap and serialized again later |
3369 | 4695 | } else { |
3370 | 4696 | Parameter param; |
3371 | if (ParseParameterProperty(¶m, err, o, it.key(), false)) { | |
3372 | material->additionalValues[it.key()] = param; | |
3373 | } | |
3374 | } | |
3375 | } | |
3376 | ||
4697 | if (ParseParameterProperty(¶m, 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(); | |
3377 | 4707 | ParseExtensionsProperty(&material->extensions, err, o); |
3378 | 4708 | ParseExtrasProperty(&(material->extras), o); |
3379 | 4709 | |
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 | ||
3380 | 4725 | return true; |
3381 | 4726 | } |
3382 | 4727 | |
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")) { | |
3389 | 4735 | if (err) { |
3390 | 4736 | (*err) += "`sampler` field is missing in animation channels\n"; |
3391 | 4737 | } |
3392 | 4738 | return false; |
3393 | 4739 | } |
3394 | 4740 | |