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

source code of qtquick3d/src/3rdparty/assimp/src/code/AssetLib/glTF2/glTF2Asset.h