1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2021, assimp team
6 
7 All rights reserved.
8 
9 Redistribution and use of this software in source and binary forms,
10 with or without modification, are permitted provided that the
11 following conditions are met:
12 
13 * Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16 
17 * Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21 
22 * Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26 
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 
39 ----------------------------------------------------------------------
40 */
41 
42 /** @file glTFAsset.h
43  * Declares a glTF class to handle gltf/glb files
44  *
45  * glTF Extensions Support:
46  *   KHR_materials_pbrSpecularGlossiness full
47  *   KHR_materials_unlit full
48  *   KHR_lights_punctual full
49  *   KHR_materials_sheen full
50  *   KHR_materials_clearcoat full
51  *   KHR_materials_transmission full
52  *   KHR_materials_volume full
53  *   KHR_materials_ior full
54  */
55 #ifndef GLTF2ASSET_H_INC
56 #define GLTF2ASSET_H_INC
57 
58 #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
59 
60 #include <assimp/Exceptional.h>
61 
62 #include <algorithm>
63 #include <list>
64 #include <map>
65 #include <set>
66 #include <stdexcept>
67 #include <string>
68 #include <vector>
69 
70 // clang-format off
71 #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
72 #pragma GCC diagnostic push
73 #pragma GCC diagnostic ignored "-Wclass-memaccess"
74 #endif
75 
76 #include <rapidjson/document.h>
77 #include <rapidjson/error/en.h>
78 #include <rapidjson/rapidjson.h>
79 #include <rapidjson/schema.h>
80 
81 #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
82 #   pragma GCC diagnostic pop
83 #endif
84 
85 #ifdef ASSIMP_API
86 #   include <assimp/ByteSwapper.h>
87 #   include <assimp/DefaultIOSystem.h>
88 #   include <memory>
89 #else
90 #   include <memory>
91 #   define AI_SWAP4(p)
92 #   define ai_assert
93 #endif
94 
95 #if _MSC_VER > 1500 || (defined __GNUC___)
96 #   define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
97 #else
98 #   define gltf_unordered_map map
99 #   define gltf_unordered_set set
100 #endif
101 
102 #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
103 #   include <unordered_map>
104 #   include <unordered_set>
105 #   if defined(_MSC_VER) && _MSC_VER <= 1600
106 #       define gltf_unordered_map tr1::unordered_map
107 #       define gltf_unordered_set tr1::unordered_set
108 #   else
109 #      define gltf_unordered_map unordered_map
110 #       define gltf_unordered_set unordered_set
111 #   endif
112 #endif
113 // clang-format on
114 
115 #include <assimp/StringUtils.h>
116 #include <assimp/material.h>
117 #include <assimp/GltfMaterial.h>
118 
119 #include "AssetLib/glTF/glTFCommon.h"
120 
121 namespace glTF2 {
122 
123 using glTFCommon::Nullable;
124 using glTFCommon::Ref;
125 using glTFCommon::IOStream;
126 using glTFCommon::IOSystem;
127 using glTFCommon::shared_ptr;
128 
129 using rapidjson::Document;
130 using rapidjson::Value;
131 
132 class Asset;
133 class AssetWriter;
134 
135 struct BufferView; // here due to cross-reference
136 struct Texture;
137 struct Skin;
138 
139 using glTFCommon::mat4;
140 using glTFCommon::vec3;
141 using glTFCommon::vec4;
142 
143 //! Magic number for GLB files
144 #define AI_GLB_MAGIC_NUMBER "glTF"
145 
146 #ifdef ASSIMP_API
147 #include <assimp/Compiler/pushpack1.h>
148 #endif
149 
150 //! For binary .glb files
151 //! 12-byte header (+ the JSON + a "body" data section)
152 struct GLB_Header {
153     uint8_t magic[4]; //!< Magic number: "glTF"
154     uint32_t version; //!< Version number (always 2 as of the last update)
155     uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes
156 } PACK_STRUCT;
157 
158 struct GLB_Chunk {
159     uint32_t chunkLength;
160     uint32_t chunkType;
161 } PACK_STRUCT;
162 
163 #ifdef ASSIMP_API
164 #include <assimp/Compiler/poppack1.h>
165 #endif
166 
167 //! Values for the GLB_Chunk::chunkType field
168 enum ChunkType {
169     ChunkType_JSON = 0x4E4F534A,
170     ChunkType_BIN = 0x004E4942
171 };
172 
173 //! Values for the mesh primitive modes
174 enum PrimitiveMode {
175     PrimitiveMode_POINTS = 0,
176     PrimitiveMode_LINES = 1,
177     PrimitiveMode_LINE_LOOP = 2,
178     PrimitiveMode_LINE_STRIP = 3,
179     PrimitiveMode_TRIANGLES = 4,
180     PrimitiveMode_TRIANGLE_STRIP = 5,
181     PrimitiveMode_TRIANGLE_FAN = 6
182 };
183 
184 //! Values for the Accessor::componentType field
185 enum ComponentType {
186     ComponentType_BYTE = 5120,
187     ComponentType_UNSIGNED_BYTE = 5121,
188     ComponentType_SHORT = 5122,
189     ComponentType_UNSIGNED_SHORT = 5123,
190     ComponentType_UNSIGNED_INT = 5125,
191     ComponentType_FLOAT = 5126
192 };
193 
ComponentTypeSize(ComponentType t)194 inline unsigned int ComponentTypeSize(ComponentType t) {
195     switch (t) {
196     case ComponentType_SHORT:
197     case ComponentType_UNSIGNED_SHORT:
198         return 2;
199 
200     case ComponentType_UNSIGNED_INT:
201     case ComponentType_FLOAT:
202         return 4;
203 
204     case ComponentType_BYTE:
205     case ComponentType_UNSIGNED_BYTE:
206         return 1;
207     default:
208         throw DeadlyImportError("GLTF: Unsupported Component Type ", ai_to_string(t));
209     }
210 }
211 
212 //! Values for the BufferView::target field
213 enum BufferViewTarget {
214     BufferViewTarget_NONE = 0,
215     BufferViewTarget_ARRAY_BUFFER = 34962,
216     BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963
217 };
218 
219 //! Values for the Sampler::magFilter field
220 enum class SamplerMagFilter : unsigned int {
221     UNSET = 0,
222     SamplerMagFilter_Nearest = 9728,
223     SamplerMagFilter_Linear = 9729
224 };
225 
226 //! Values for the Sampler::minFilter field
227 enum class SamplerMinFilter : unsigned int {
228     UNSET = 0,
229     SamplerMinFilter_Nearest = 9728,
230     SamplerMinFilter_Linear = 9729,
231     SamplerMinFilter_Nearest_Mipmap_Nearest = 9984,
232     SamplerMinFilter_Linear_Mipmap_Nearest = 9985,
233     SamplerMinFilter_Nearest_Mipmap_Linear = 9986,
234     SamplerMinFilter_Linear_Mipmap_Linear = 9987
235 };
236 
237 //! Values for the Sampler::wrapS and Sampler::wrapT field
238 enum class SamplerWrap : unsigned int {
239     UNSET = 0,
240     Clamp_To_Edge = 33071,
241     Mirrored_Repeat = 33648,
242     Repeat = 10497
243 };
244 
245 //! Values for the Texture::format and Texture::internalFormat fields
246 enum TextureFormat {
247     TextureFormat_ALPHA = 6406,
248     TextureFormat_RGB = 6407,
249     TextureFormat_RGBA = 6408,
250     TextureFormat_LUMINANCE = 6409,
251     TextureFormat_LUMINANCE_ALPHA = 6410
252 };
253 
254 //! Values for the Texture::target field
255 enum TextureTarget {
256     TextureTarget_TEXTURE_2D = 3553
257 };
258 
259 //! Values for the Texture::type field
260 enum TextureType {
261     TextureType_UNSIGNED_BYTE = 5121,
262     TextureType_UNSIGNED_SHORT_5_6_5 = 33635,
263     TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819,
264     TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820
265 };
266 
267 //! Values for the Animation::Target::path field
268 enum AnimationPath {
269     AnimationPath_TRANSLATION,
270     AnimationPath_ROTATION,
271     AnimationPath_SCALE,
272     AnimationPath_WEIGHTS,
273 };
274 
275 //! Values for the Animation::Sampler::interpolation field
276 enum Interpolation {
277     Interpolation_LINEAR,
278     Interpolation_STEP,
279     Interpolation_CUBICSPLINE,
280 };
281 
282 //! Values for the Accessor::type field (helper class)
283 class AttribType {
284 public:
285     enum Value { SCALAR,
286         VEC2,
287         VEC3,
288         VEC4,
289         MAT2,
290         MAT3,
291         MAT4 };
292 
293 private:
294     static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
295 
296     struct Info {
297         const char *name;
298         unsigned int numComponents;
299     };
300 
301     template <int N>
302     struct data { static const Info infos[NUM_VALUES]; };
303 
304 public:
FromString(const char * str)305     inline static Value FromString(const char *str) {
306         for (size_t i = 0; i < NUM_VALUES; ++i) {
307             if (strcmp(data<0>::infos[i].name, str) == 0) {
308                 return static_cast<Value>(i);
309             }
310         }
311         return SCALAR;
312     }
313 
ToString(Value type)314     inline static const char *ToString(Value type) {
315         return data<0>::infos[static_cast<size_t>(type)].name;
316     }
317 
GetNumComponents(Value type)318     inline static unsigned int GetNumComponents(Value type) {
319         return data<0>::infos[static_cast<size_t>(type)].numComponents;
320     }
321 };
322 
323 // must match the order of the AttribTypeTraits::Value enum!
324 template <int N>
325 const AttribType::Info
326         AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
327             { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
328         };
329 
330 
331 struct CustomExtension {
332 
333     //
334     // A struct containing custom extension data added to a glTF2 file
335     // Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum
336     // String, Double, Uint64, and Int64 are stored in the Nullables
337     // Object and Array are stored in the std::vector
338     //
339     std::string name;
340 
341     Nullable<std::string> mStringValue;
342     Nullable<double> mDoubleValue;
343     Nullable<uint64_t> mUint64Value;
344     Nullable<int64_t> mInt64Value;
345     Nullable<bool> mBoolValue;
346 
347     // std::vector<CustomExtension> handles both Object and Array
348     Nullable<std::vector<CustomExtension>> mValues;
349 
350     operator bool() const {
351         return Size() != 0;
352     }
353 
SizeCustomExtension354     size_t Size() const {
355         if (mValues.isPresent) {
356             return mValues.value.size();
357         } else if (mStringValue.isPresent || mDoubleValue.isPresent || mUint64Value.isPresent || mInt64Value.isPresent || mBoolValue.isPresent) {
358             return 1;
359         }
360         return 0;
361     }
362 
363     CustomExtension() = default;
364 
365     ~CustomExtension() = default;
366 
CustomExtensionCustomExtension367     CustomExtension(const CustomExtension &other) :
368             name(other.name),
369             mStringValue(other.mStringValue),
370             mDoubleValue(other.mDoubleValue),
371             mUint64Value(other.mUint64Value),
372             mInt64Value(other.mInt64Value),
373             mBoolValue(other.mBoolValue),
374             mValues(other.mValues) {
375         // empty
376     }
377 };
378 
379 //! Base class for all glTF top-level objects
380 struct Object {
381     int index; //!< The index of this object within its property container
382     int oIndex; //!< The original index of this object defined in the JSON
383     std::string id; //!< The globally unique ID used to reference this object
384     std::string name; //!< The user-defined name of this object
385 
386     CustomExtension customExtensions;
387     CustomExtension extras;
388 
389     //! Objects marked as special are not exported (used to emulate the binary body buffer)
IsSpecialObject390     virtual bool IsSpecial() const { return false; }
391 
~ObjectObject392     virtual ~Object() {}
393 
394     //! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
TranslateIdObject395     static const char *TranslateId(Asset & /*r*/, const char *id) { return id; }
396 
397     inline Value *FindString(Value &val, const char *id);
398     inline Value *FindNumber(Value &val, const char *id);
399     inline Value *FindUInt(Value &val, const char *id);
400     inline Value *FindArray(Value &val, const char *id);
401     inline Value *FindObject(Value &val, const char *id);
402     inline Value *FindExtension(Value &val, const char *extensionId);
403 
404     inline void ReadExtensions(Value &val);
405     inline void ReadExtras(Value &val);
406 };
407 
408 //
409 // Classes for each glTF top-level object type
410 //
411 
412 //! A buffer points to binary geometry, animation, or skins.
413 struct Buffer : public Object {
414     /********************* Types *********************/
415 public:
416     enum Type {
417         Type_arraybuffer,
418         Type_text
419     };
420 
421     /// \struct SEncodedRegion
422     /// Descriptor of encoded region in "bufferView".
423     struct SEncodedRegion {
424         const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
425         const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
426         uint8_t *const DecodedData; ///< Cached encoded data.
427         const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
428         const std::string ID; ///< ID of the region.
429 
430         /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
431         /// Constructor.
432         /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
433         /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
434         /// \param [in] pDecodedData - pointer to decoded data array.
435         /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
436         /// \param [in] pID - ID of the region.
SEncodedRegionBuffer::SEncodedRegion437         SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
438                 Offset(pOffset),
439                 EncodedData_Length(pEncodedData_Length),
440                 DecodedData(pDecodedData),
441                 DecodedData_Length(pDecodedData_Length),
442                 ID(pID) {}
443 
444         /// \fn ~SEncodedRegion()
445         /// Destructor.
~SEncodedRegionBuffer::SEncodedRegion446         ~SEncodedRegion() { delete[] DecodedData; }
447     };
448 
449     /******************* Variables *******************/
450 
451     //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
452     size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
453     //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
454     size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0)
455 
456     Type type;
457 
458     /// \var EncodedRegion_Current
459     /// Pointer to currently active encoded region.
460     /// Why not decoding all regions at once and not to set one buffer with decoded data?
461     /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded
462     /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But
463     /// offset is counted for another regions is encoded.
464     /// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data:
465     /// M1_E0, M1_E1, M2_E0, M2_E1.
466     /// After decoding you'll get:
467     /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3.
468     /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like
469     /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4}
470     /// but in real life you'll get:
471     /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4}
472     /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded.
473     /// And when before you start to read data of current mesh (with encoded data of course) you must decode region of "bufferView", after read finished
474     /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data.
475     ///
476     /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in
477     /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory.
478     SEncodedRegion *EncodedRegion_Current;
479 
480 private:
481     shared_ptr<uint8_t> mData; //!< Pointer to the data
482     bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
483 
484     /// \var EncodedRegion_List
485     /// List of encoded regions.
486     std::list<SEncodedRegion *> EncodedRegion_List;
487 
488     /******************* Functions *******************/
489 
490 public:
491     Buffer();
492     ~Buffer();
493 
494     void Read(Value &obj, Asset &r);
495 
496     bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
497 
498     /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
499     /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
500     /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
501     /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
502     /// \param [in] pDecodedData - pointer to decoded data array.
503     /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
504     /// \param [in] pID - ID of the region.
505     void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
506 
507     /// \fn void EncodedRegion_SetCurrent(const std::string& pID)
508     /// Select current encoded region by ID. \sa EncodedRegion_Current.
509     /// \param [in] pID - ID of the region.
510     void EncodedRegion_SetCurrent(const std::string &pID);
511 
512     /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
513     /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
514     /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
515     /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
516     /// \param [in] pReplace_Data - pointer to array with new data for buffer.
517     /// \param [in] pReplace_Count - count of bytes in new data.
518     /// \return true - if successfully replaced, false if input arguments is out of range.
519     bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count);
520     bool ReplaceData_joint(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count);
521 
522     size_t AppendData(uint8_t *data, size_t length);
523     void Grow(size_t amount);
524 
GetPointerBuffer525     uint8_t *GetPointer() { return mData.get(); }
526 
MarkAsSpecialBuffer527     void MarkAsSpecial() { mIsSpecial = true; }
528 
IsSpecialBuffer529     bool IsSpecial() const override { return mIsSpecial; }
530 
GetURIBuffer531     std::string GetURI() { return std::string(this->id) + ".bin"; }
532 
533     static const char *TranslateId(Asset &r, const char *id);
534 };
535 
536 //! A view into a buffer generally representing a subset of the buffer.
537 struct BufferView : public Object {
538     Ref<Buffer> buffer; //! The ID of the buffer. (required)
539     size_t byteOffset; //! The offset into the buffer in bytes. (required)
540     size_t byteLength; //! The length of the bufferView in bytes. (default: 0)
541     unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
542 
543     BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
544 
545     void Read(Value &obj, Asset &r);
546     uint8_t *GetPointer(size_t accOffset);
547 };
548 
549 //! A typed view into a BufferView. A BufferView contains raw binary data.
550 //! An accessor provides a typed view into a BufferView or a subset of a BufferView
551 //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer.
552 struct Accessor : public Object {
553     struct Sparse;
554 
555     Ref<BufferView> bufferView; //!< The ID of the bufferView. (required)
556     size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required)
557     ComponentType componentType; //!< The datatype of components in the attribute. (required)
558     size_t count; //!< The number of attributes referenced by this accessor. (required)
559     AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
560     std::vector<double> max; //!< Maximum value of each component in this attribute.
561     std::vector<double> min; //!< Minimum value of each component in this attribute.
562     std::unique_ptr<Sparse> sparse;
563     std::unique_ptr<Buffer> decodedBuffer; // Packed decoded data, returned instead of original bufferView if present
564 
565     unsigned int GetNumComponents();
566     unsigned int GetBytesPerComponent();
567     unsigned int GetElementSize();
568 
569     inline uint8_t *GetPointer();
570     inline size_t GetStride();
571     inline size_t GetMaxByteSize();
572 
573     template <class T>
574     void ExtractData(T *&outData);
575 
576     void WriteData(size_t count, const void *src_buffer, size_t src_stride);
577     void WriteSparseValues(size_t count, const void *src_data, size_t src_dataStride);
578     void WriteSparseIndices(size_t count, const void *src_idx, size_t src_idxStride);
579 
580     //! Helper class to iterate the data
581     class Indexer {
582         friend struct Accessor;
583 
584         // This field is reported as not used, making it protectd is the easiest way to work around it without going to the bottom of what the problem is:
585         // ../code/glTF2/glTF2Asset.h:392:19: error: private field 'accessor' is not used [-Werror,-Wunused-private-field]
586     protected:
587         Accessor &accessor;
588 
589     private:
590         uint8_t *data;
591         size_t elemSize, stride;
592 
593         Indexer(Accessor &acc);
594 
595     public:
596         //! Accesses the i-th value as defined by the accessor
597         template <class T>
598         T GetValue(int i);
599 
600         //! Accesses the i-th value as defined by the accessor
GetUIntAccessor601         inline unsigned int GetUInt(int i) {
602             return GetValue<unsigned int>(i);
603         }
604 
IsValidAccessor605         inline bool IsValid() const {
606             return data != nullptr;
607         }
608     };
609 
GetIndexerAccessor610     inline Indexer GetIndexer() {
611         return Indexer(*this);
612     }
613 
AccessorAccessor614     Accessor() {}
615     void Read(Value &obj, Asset &r);
616 
617     //sparse
618     struct Sparse {
619         size_t count;
620         ComponentType indicesType;
621         Ref<BufferView> indices;
622         size_t indicesByteOffset;
623         Ref<BufferView> values;
624         size_t valuesByteOffset;
625 
626         std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
627 
628         void PopulateData(size_t numBytes, uint8_t *bytes);
629         void PatchData(unsigned int elementSize);
630     };
631 };
632 
633 struct Camera : public Object {
634     enum Type {
635         Perspective,
636         Orthographic
637     };
638 
639     Type type;
640 
641     union {
642         struct {
643             float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
644             float yfov; //!<The floating - point vertical field of view in radians. (required)
645             float zfar; //!<The floating - point distance to the far clipping plane. (required)
646             float znear; //!< The floating - point distance to the near clipping plane. (required)
647         } perspective;
648 
649         struct {
650             float xmag; //! The floating-point horizontal magnification of the view. (required)
651             float ymag; //! The floating-point vertical magnification of the view. (required)
652             float zfar; //! The floating-point distance to the far clipping plane. (required)
653             float znear; //! The floating-point distance to the near clipping plane. (required)
654         } ortographic;
655     } cameraProperties;
656 
CameraCamera657     Camera() :
658             type(Perspective),
659             cameraProperties() {
660         // empty
661     }
662     void Read(Value &obj, Asset &r);
663 };
664 
665 //! A light (from KHR_lights_punctual extension)
666 struct Light : public Object {
667     enum Type {
668         Directional,
669         Point,
670         Spot
671     };
672 
673     Type type;
674 
675     vec3 color;
676     float intensity;
677     Nullable<float> range;
678 
679     float innerConeAngle;
680     float outerConeAngle;
681 
LightLight682     Light() {}
683     void Read(Value &obj, Asset &r);
684 };
685 
686 //! Image data used to create a texture.
687 struct Image : public Object {
688     std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
689 
690     Ref<BufferView> bufferView;
691 
692     std::string mimeType;
693 
694     int width, height;
695 
696 private:
697     std::unique_ptr<uint8_t[]> mData;
698     size_t mDataLength;
699 
700 public:
701     Image();
702     void Read(Value &obj, Asset &r);
703 
HasDataImage704     inline bool HasData() const { return mDataLength > 0; }
705 
GetDataLengthImage706     inline size_t GetDataLength() const { return mDataLength; }
707 
GetDataImage708     inline const uint8_t *GetData() const { return mData.get(); }
709 
710     inline uint8_t *StealData();
711 
712     inline void SetData(uint8_t *data, size_t length, Asset &r);
713 };
714 
715 const vec4 defaultBaseColor = { 1, 1, 1, 1 };
716 const vec3 defaultEmissiveFactor = { 0, 0, 0 };
717 const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 };
718 const vec3 defaultSpecularFactor = { 1, 1, 1 };
719 const vec3 defaultSheenFactor = { 0, 0, 0 };
720 const vec3 defaultAttenuationColor = { 1, 1, 1 };
721 
722 struct TextureInfo {
723     Ref<Texture> texture;
724     unsigned int index;
725     unsigned int texCoord = 0;
726 
727     bool textureTransformSupported = false;
728     struct TextureTransformExt {
729         float offset[2];
730         float rotation;
731         float scale[2];
732     } TextureTransformExt_t;
733 };
734 
735 struct NormalTextureInfo : TextureInfo {
736     float scale = 1;
737 };
738 
739 struct OcclusionTextureInfo : TextureInfo {
740     float strength = 1;
741 };
742 
743 struct PbrMetallicRoughness {
744     vec4 baseColorFactor;
745     TextureInfo baseColorTexture;
746     TextureInfo metallicRoughnessTexture;
747     float metallicFactor;
748     float roughnessFactor;
749 };
750 
751 struct PbrSpecularGlossiness {
752     vec4 diffuseFactor;
753     vec3 specularFactor;
754     float glossinessFactor;
755     TextureInfo diffuseTexture;
756     TextureInfo specularGlossinessTexture;
757 
PbrSpecularGlossinessPbrSpecularGlossiness758     PbrSpecularGlossiness() { SetDefaults(); }
759     void SetDefaults();
760 };
761 
762 struct MaterialSheen {
763     vec3 sheenColorFactor;
764     float sheenRoughnessFactor;
765     TextureInfo sheenColorTexture;
766     TextureInfo sheenRoughnessTexture;
767 
MaterialSheenMaterialSheen768     MaterialSheen() { SetDefaults(); }
769     void SetDefaults();
770 };
771 
772 struct MaterialClearcoat {
773     float clearcoatFactor = 0.f;
774     float clearcoatRoughnessFactor = 0.f;
775     TextureInfo clearcoatTexture;
776     TextureInfo clearcoatRoughnessTexture;
777     NormalTextureInfo clearcoatNormalTexture;
778 };
779 
780 struct MaterialTransmission {
781     TextureInfo transmissionTexture;
782     float transmissionFactor = 0.f;
783 };
784 
785 struct MaterialVolume {
786     float thicknessFactor = 0.f;
787     TextureInfo thicknessTexture;
788     float attenuationDistance = 0.f;
789     vec3 attenuationColor;
790 
MaterialVolumeMaterialVolume791     MaterialVolume() { SetDefaults(); }
792     void SetDefaults();
793 };
794 
795 struct MaterialIOR {
796     float ior = 0.f;
797 
MaterialIORMaterialIOR798     MaterialIOR() { SetDefaults(); }
799     void SetDefaults();
800 };
801 
802 //! The material appearance of a primitive.
803 struct Material : public Object {
804     //PBR metallic roughness properties
805     PbrMetallicRoughness pbrMetallicRoughness;
806 
807     //other basic material properties
808     NormalTextureInfo normalTexture;
809     OcclusionTextureInfo occlusionTexture;
810     TextureInfo emissiveTexture;
811     vec3 emissiveFactor;
812     std::string alphaMode;
813     float alphaCutoff;
814     bool doubleSided;
815 
816     //extension: KHR_materials_pbrSpecularGlossiness
817     Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
818 
819     //extension: KHR_materials_sheen
820     Nullable<MaterialSheen> materialSheen;
821 
822     //extension: KHR_materials_clearcoat
823     Nullable<MaterialClearcoat> materialClearcoat;
824 
825     //extension: KHR_materials_transmission
826     Nullable<MaterialTransmission> materialTransmission;
827 
828     //extension: KHR_materials_volume
829     Nullable<MaterialVolume> materialVolume;
830 
831     //extension: KHR_materials_ior
832     Nullable<MaterialIOR> materialIOR;
833 
834     //extension: KHR_materials_unlit
835     bool unlit;
836 
MaterialMaterial837     Material() { SetDefaults(); }
838     void Read(Value &obj, Asset &r);
839     void SetDefaults();
840 
841     inline void SetTextureProperties(Asset &r, Value *prop, TextureInfo &out);
842     inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out);
843     inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out);
844     inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out);
845 };
846 
847 //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene.
848 struct Mesh : public Object {
849     using AccessorList = std::vector<Ref<Accessor>>;
850 
851     struct Primitive {
852         PrimitiveMode mode;
853 
854         struct Attributes {
855             AccessorList position, normal, tangent, texcoord, color, joint, jointmatrix, weight;
856         } attributes;
857 
858         Ref<Accessor> indices;
859 
860         Ref<Material> material;
861 
862         struct Target {
863             AccessorList position, normal, tangent;
864         };
865         std::vector<Target> targets;
866 
867         // extension: FB_ngon_encoding
868         bool ngonEncoded;
869 
PrimitiveMesh::Primitive870         Primitive(): ngonEncoded(false) {}
871     };
872 
873     std::vector<Primitive> primitives;
874 
875     std::vector<float> weights;
876     std::vector<std::string> targetNames;
877 
MeshMesh878     Mesh() {}
879 
880     /// Get mesh data from JSON-object and place them to root asset.
881     /// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
882     /// \param [out] pAsset_Root - reference to root asset where data will be stored.
883     void Read(Value &pJSON_Object, Asset &pAsset_Root);
884 };
885 
886 struct Node : public Object {
887     std::vector<Ref<Node>> children;
888     std::vector<Ref<Mesh>> meshes;
889 
890     Nullable<mat4> matrix;
891     Nullable<vec3> translation;
892     Nullable<vec4> rotation;
893     Nullable<vec3> scale;
894 
895     Ref<Camera> camera;
896     Ref<Light> light;
897 
898     std::vector<Ref<Node>> skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
899     Ref<Skin> skin; //!< The ID of the skin referenced by this node.
900     std::string jointName; //!< Name used when this node is a joint in a skin.
901 
902     Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
903 
NodeNode904     Node() {}
905     void Read(Value &obj, Asset &r);
906 };
907 
908 struct Program : public Object {
ProgramProgram909     Program() {}
910     void Read(Value &obj, Asset &r);
911 };
912 
913 struct Sampler : public Object {
914     SamplerMagFilter magFilter; //!< The texture magnification filter.
915     SamplerMinFilter minFilter; //!< The texture minification filter.
916     SamplerWrap wrapS; //!< The texture wrapping in the S direction.
917     SamplerWrap wrapT; //!< The texture wrapping in the T direction.
918 
SamplerSampler919     Sampler() { SetDefaults(); }
920     void Read(Value &obj, Asset &r);
921     void SetDefaults();
922 };
923 
924 struct Scene : public Object {
925     std::string name;
926     std::vector<Ref<Node>> nodes;
927 
SceneScene928     Scene() {}
929     void Read(Value &obj, Asset &r);
930 };
931 
932 struct Shader : public Object {
ShaderShader933     Shader() {}
934     void Read(Value &obj, Asset &r);
935 };
936 
937 struct Skin : public Object {
938     Nullable<mat4> bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order.
939     Ref<Accessor> inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices.
940     std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
941     std::string name; //!< The user-defined name of this object.
942 
SkinSkin943     Skin() {}
944     void Read(Value &obj, Asset &r);
945 };
946 
947 //! A texture and its sampler.
948 struct Texture : public Object {
949     Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
950     Ref<Image> source; //!< The ID of the image used by this texture. (required)
951 
952     //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
953     //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
954 
955     //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
956     //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
957 
TextureTexture958     Texture() {}
959     void Read(Value &obj, Asset &r);
960 };
961 
962 struct Animation : public Object {
963     struct Sampler {
SamplerAnimation::Sampler964         Sampler() :
965                 interpolation(Interpolation_LINEAR) {}
966 
967         Ref<Accessor> input; //!< Accessor reference to the buffer storing the key-frame times.
968         Ref<Accessor> output; //!< Accessor reference to the buffer storing the key-frame values.
969         Interpolation interpolation; //!< Type of interpolation algorithm to use between key-frames.
970     };
971 
972     struct Target {
TargetAnimation::Target973         Target() :
974                 path(AnimationPath_TRANSLATION) {}
975 
976         Ref<Node> node; //!< The node to animate.
977         AnimationPath path; //!< The property of the node to animate.
978     };
979 
980     struct Channel {
ChannelAnimation::Channel981         Channel() :
982                 sampler(-1) {}
983 
984         int sampler; //!< The sampler index containing the animation data.
985         Target target; //!< The node and property to animate.
986     };
987 
988     std::vector<Sampler> samplers; //!< All the key-frame data for this animation.
989     std::vector<Channel> channels; //!< Data to connect nodes to key-frames.
990 
AnimationAnimation991     Animation() {}
992     void Read(Value &obj, Asset &r);
993 };
994 
995 //! Base class for LazyDict that acts as an interface
996 class LazyDictBase {
997 public:
~LazyDictBase()998     virtual ~LazyDictBase() {}
999 
1000     virtual void AttachToDocument(Document &doc) = 0;
1001     virtual void DetachFromDocument() = 0;
1002 
1003 #if !defined(ASSIMP_BUILD_NO_EXPORT)
1004     virtual void WriteObjects(AssetWriter &writer) = 0;
1005 #endif
1006 };
1007 
1008 template <class T>
1009 class LazyDict;
1010 
1011 //! (Implemented in glTFAssetWriter.h)
1012 template <class T>
1013 void WriteLazyDict(LazyDict<T> &d, AssetWriter &w);
1014 
1015 //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID
1016 //! It is the owner the loaded objects, so when it is destroyed it also deletes them
1017 template <class T>
1018 class LazyDict : public LazyDictBase {
1019     friend class Asset;
1020     friend class AssetWriter;
1021 
1022     using Dict = typename std::gltf_unordered_map<unsigned int, unsigned int>;
1023     using IdDict = typename std::gltf_unordered_map<std::string, unsigned int>;
1024 
1025     std::vector<T *> mObjs; //! The read objects
1026     Dict mObjsByOIndex; //! The read objects accessible by original index
1027     IdDict mObjsById; //! The read objects accessible by id
1028     const char *mDictId; //! ID of the dictionary object
1029     const char *mExtId; //! ID of the extension defining the dictionary
1030     Value *mDict; //! JSON dictionary object
1031     Asset &mAsset; //! The asset instance
1032 
1033     std::gltf_unordered_set<unsigned int> mRecursiveReferenceCheck; //! Used by Retrieve to prevent recursive lookups
1034 
1035     void AttachToDocument(Document &doc);
1036     void DetachFromDocument();
1037 
1038 #if !defined(ASSIMP_BUILD_NO_EXPORT)
WriteObjects(AssetWriter & writer)1039     void WriteObjects(AssetWriter &writer) { WriteLazyDict<T>(*this, writer); }
1040 #endif
1041 
1042     Ref<T> Add(T *obj);
1043 
1044 public:
1045     LazyDict(Asset &asset, const char *dictId, const char *extId = 0);
1046     ~LazyDict();
1047 
1048     Ref<T> Retrieve(unsigned int i);
1049 
1050     Ref<T> Get(unsigned int i);
1051     Ref<T> Get(const char *id);
1052 
1053     Ref<T> Create(const char *id);
Create(const std::string & id)1054     Ref<T> Create(const std::string &id) { return Create(id.c_str()); }
1055 
1056     unsigned int Remove(const char *id);
1057 
Size()1058     inline unsigned int Size() const { return unsigned(mObjs.size()); }
1059 
1060     inline T &operator[](size_t i) { return *mObjs[i]; }
1061 };
1062 
1063 struct AssetMetadata {
1064     std::string copyright; //!< A copyright message suitable for display to credit the content creator.
1065     std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
1066 
1067     struct {
1068         std::string api; //!< Specifies the target rendering API (default: "WebGL")
1069         std::string version; //!< Specifies the target rendering API (default: "1.0.3")
1070     } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
1071 
1072     std::string version; //!< The glTF format version
1073 
1074     void Read(Document &doc);
1075 
AssetMetadataAssetMetadata1076     AssetMetadata() :
1077             version() {}
1078 };
1079 
1080 //
1081 // glTF Asset class
1082 //
1083 
1084 //! Root object for a glTF asset
1085 class Asset {
1086     using IdMap = std::gltf_unordered_map<std::string, int>;
1087 
1088     template <class T>
1089     friend class LazyDict;
1090 
1091     friend struct Buffer; // To access OpenFile
1092 
1093     friend class AssetWriter;
1094 
1095 private:
1096     IOSystem *mIOSystem;
1097     rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
1098 
1099     std::string mCurrentAssetDir;
1100 
1101     size_t mSceneLength;
1102     size_t mBodyOffset, mBodyLength;
1103 
1104     std::vector<LazyDictBase *> mDicts;
1105 
1106     IdMap mUsedIds;
1107 
1108     Ref<Buffer> mBodyBuffer;
1109 
1110     Asset(Asset &);
1111     Asset &operator=(const Asset &);
1112 
1113 public:
1114     //! Keeps info about the enabled extensions
1115     struct Extensions {
1116         bool KHR_materials_pbrSpecularGlossiness;
1117         bool KHR_materials_unlit;
1118         bool KHR_lights_punctual;
1119         bool KHR_texture_transform;
1120         bool KHR_materials_sheen;
1121         bool KHR_materials_clearcoat;
1122         bool KHR_materials_transmission;
1123         bool KHR_materials_volume;
1124         bool KHR_materials_ior;
1125         bool KHR_draco_mesh_compression;
1126         bool FB_ngon_encoding;
1127         bool KHR_texture_basisu;
1128     } extensionsUsed;
1129 
1130     //! Keeps info about the required extensions
1131     struct RequiredExtensions {
1132         bool KHR_draco_mesh_compression;
1133         bool KHR_texture_basisu;
1134     } extensionsRequired;
1135 
1136     AssetMetadata asset;
1137     Value *extras = nullptr;
1138 
1139     // Dictionaries for each type of object
1140 
1141     LazyDict<Accessor> accessors;
1142     LazyDict<Animation> animations;
1143     LazyDict<Buffer> buffers;
1144     LazyDict<BufferView> bufferViews;
1145     LazyDict<Camera> cameras;
1146     LazyDict<Light> lights;
1147     LazyDict<Image> images;
1148     LazyDict<Material> materials;
1149     LazyDict<Mesh> meshes;
1150     LazyDict<Node> nodes;
1151     LazyDict<Sampler> samplers;
1152     LazyDict<Scene> scenes;
1153     LazyDict<Skin> skins;
1154     LazyDict<Texture> textures;
1155 
1156     Ref<Scene> scene;
1157 
1158 public:
1159     Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
mIOSystem(io)1160             mIOSystem(io),
1161             mSchemaDocumentProvider(schemaDocumentProvider),
1162             asset(),
1163             accessors(*this, "accessors"),
1164             animations(*this, "animations"),
1165             buffers(*this, "buffers"),
1166             bufferViews(*this, "bufferViews"),
1167             cameras(*this, "cameras"),
1168             lights(*this, "lights", "KHR_lights_punctual"),
1169             images(*this, "images"),
1170             materials(*this, "materials"),
1171             meshes(*this, "meshes"),
1172             nodes(*this, "nodes"),
1173             samplers(*this, "samplers"),
1174             scenes(*this, "scenes"),
1175             skins(*this, "skins"),
1176             textures(*this, "textures") {
1177         memset(&extensionsUsed, 0, sizeof(extensionsUsed));
1178         memset(&extensionsRequired, 0, sizeof(extensionsRequired));
1179     }
1180 
1181     //! Main function
1182     void Load(const std::string &file, bool isBinary = false);
1183 
1184     //! Parse the AssetMetadata and check that the version is 2.
1185     bool CanRead(const std::string &pFile, bool isBinary = false);
1186 
1187     //! Enables binary encoding on the asset
1188     void SetAsBinary();
1189 
1190     //! Search for an available name, starting from the given strings
1191     std::string FindUniqueID(const std::string &str, const char *suffix);
1192 
GetBodyBuffer()1193     Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
1194 
1195 private:
1196     void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
1197 
1198     //! Obtain a JSON document from the stream.
1199     // \param second argument is a buffer used by the document. It must be kept
1200     // alive while the document is in use.
1201     Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
1202 
1203     void ReadExtensionsUsed(Document &doc);
1204     void ReadExtensionsRequired(Document &doc);
1205 
1206     IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
1207 };
1208 
getContextForErrorMessages(const std::string & id,const std::string & name)1209 inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {
1210     std::string context = id;
1211     if (!name.empty()) {
1212         context += " (\"" + name + "\")";
1213     }
1214     return context;
1215 }
1216 
1217 } // namespace glTF2
1218 
1219 // Include the implementation of the methods
1220 #include "glTF2Asset.inl"
1221 
1222 #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
1223 
1224 #endif // GLTF2ASSET_H_INC
1225