Coverage Report

Created: 2026-04-29 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/glTF/glTFAsset.h
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, 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_binary_glTF: full
47
 *   KHR_materials_common: full
48
 */
49
#ifndef GLTFASSET_H_INC
50
#define GLTFASSET_H_INC
51
52
#include "AssetLib/glTFCommon/glTFCommon.h"
53
#include <assimp/Exceptional.h>
54
#include <list>
55
#include <string>
56
#include <vector>
57
58
// clang-format off
59
60
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
61
#pragma GCC diagnostic push
62
#pragma GCC diagnostic ignored "-Wclass-memaccess"
63
#endif
64
65
#include <rapidjson/rapidjson.h>
66
#include <rapidjson/document.h>
67
#include <rapidjson/error/en.h>
68
69
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
70
#pragma GCC diagnostic pop
71
#endif
72
73
#ifdef ASSIMP_API
74
#   include <memory>
75
#   include <assimp/DefaultIOSystem.h>
76
#   include <assimp/ByteSwapper.h>
77
#else
78
#   include <memory>
79
#   define AI_SWAP4(p)
80
#   define ai_assert
81
#endif
82
83
84
#if _MSC_VER > 1500 || (defined __GNUC__)
85
#       define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
86
#   else
87
#       define gltf_unordered_map map
88
#endif
89
90
#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
91
#   include <unordered_map>
92
#   if defined(_MSC_VER) && _MSC_VER <= 1600
93
#       define gltf_unordered_map tr1::unordered_map
94
#   else
95
#       define gltf_unordered_map unordered_map
96
#   endif
97
#endif
98
99
// clang-format on
100
101
#include "AssetLib/glTFCommon/glTFCommon.h"
102
103
namespace glTF {
104
105
using glTFCommon::IOStream;
106
using glTFCommon::IOSystem;
107
using glTFCommon::Nullable;
108
using glTFCommon::Ref;
109
using glTFCommon::shared_ptr;
110
111
using rapidjson::Document;
112
using rapidjson::Value;
113
114
class Asset;
115
class AssetWriter;
116
117
struct BufferView; // here due to cross-reference
118
struct Texture;
119
struct Light;
120
struct Skin;
121
122
using glTFCommon::mat4;
123
using glTFCommon::vec3;
124
using glTFCommon::vec4;
125
126
//! Magic number for GLB files
127
25.9k
#define AI_GLB_MAGIC_NUMBER "glTF"
128
129
// clang-format off
130
#ifdef ASSIMP_API
131
#   include <assimp/Compiler/pushpack1.h>
132
#endif
133
// clang-format on
134
135
//! For the KHR_binary_glTF extension (binary .glb file)
136
//! 20-byte header (+ the JSON + a "body" data section)
137
struct GLB_Header {
138
    uint8_t magic[4]; //!< Magic number: "glTF"
139
    uint32_t version; //!< Version number (always 1 as of the last update)
140
    uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes
141
    uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
142
    uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
143
} PACK_STRUCT;
144
145
// clang-format off
146
#ifdef ASSIMP_API
147
#   include <assimp/Compiler/poppack1.h>
148
#endif
149
// clang-format on
150
151
//! Values for the GLB_Header::sceneFormat field
152
enum SceneFormat {
153
    SceneFormat_JSON = 0
154
};
155
156
//! Values for the mesh primitive modes
157
enum PrimitiveMode {
158
    PrimitiveMode_POINTS = 0,
159
    PrimitiveMode_LINES = 1,
160
    PrimitiveMode_LINE_LOOP = 2,
161
    PrimitiveMode_LINE_STRIP = 3,
162
    PrimitiveMode_TRIANGLES = 4,
163
    PrimitiveMode_TRIANGLE_STRIP = 5,
164
    PrimitiveMode_TRIANGLE_FAN = 6
165
};
166
167
//! Values for the Accessor::componentType field
168
enum ComponentType {
169
    ComponentType_BYTE = 5120,
170
    ComponentType_UNSIGNED_BYTE = 5121,
171
    ComponentType_SHORT = 5122,
172
    ComponentType_UNSIGNED_SHORT = 5123,
173
    ComponentType_UNSIGNED_INT = 5125,
174
    ComponentType_FLOAT = 5126
175
};
176
177
0
inline unsigned int ComponentTypeSize(ComponentType t) {
178
0
    switch (t) {
179
0
    case ComponentType_SHORT:
180
0
    case ComponentType_UNSIGNED_SHORT:
181
0
        return 2;
182
183
0
    case ComponentType_UNSIGNED_INT:
184
0
    case ComponentType_FLOAT:
185
0
        return 4;
186
187
0
    case ComponentType_BYTE:
188
0
    case ComponentType_UNSIGNED_BYTE:
189
0
        return 1;
190
0
    default:
191
0
        std::string err = "GLTF: Unsupported Component Type ";
192
0
        err += std::to_string(t);
193
0
        throw DeadlyImportError(err);
194
0
    }
195
0
}
196
197
//! Values for the BufferView::target field
198
enum BufferViewTarget {
199
    BufferViewTarget_NONE = 0,
200
    BufferViewTarget_ARRAY_BUFFER = 34962,
201
    BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963
202
};
203
204
//! Values for the Sampler::magFilter field
205
enum SamplerMagFilter {
206
    SamplerMagFilter_Nearest = 9728,
207
    SamplerMagFilter_Linear = 9729
208
};
209
210
//! Values for the Sampler::minFilter field
211
enum SamplerMinFilter {
212
    SamplerMinFilter_Nearest = 9728,
213
    SamplerMinFilter_Linear = 9729,
214
    SamplerMinFilter_Nearest_Mipmap_Nearest = 9984,
215
    SamplerMinFilter_Linear_Mipmap_Nearest = 9985,
216
    SamplerMinFilter_Nearest_Mipmap_Linear = 9986,
217
    SamplerMinFilter_Linear_Mipmap_Linear = 9987
218
};
219
220
//! Values for the Sampler::wrapS and Sampler::wrapT field
221
enum SamplerWrap {
222
    SamplerWrap_Clamp_To_Edge = 33071,
223
    SamplerWrap_Mirrored_Repeat = 33648,
224
    SamplerWrap_Repeat = 10497
225
};
226
227
//! Values for the Texture::format and Texture::internalFormat fields
228
enum TextureFormat {
229
    TextureFormat_ALPHA = 6406,
230
    TextureFormat_RGB = 6407,
231
    TextureFormat_RGBA = 6408,
232
    TextureFormat_LUMINANCE = 6409,
233
    TextureFormat_LUMINANCE_ALPHA = 6410
234
};
235
236
//! Values for the Texture::target field
237
enum TextureTarget {
238
    TextureTarget_TEXTURE_2D = 3553
239
};
240
241
//! Values for the Texture::type field
242
enum TextureType {
243
    TextureType_UNSIGNED_BYTE = 5121,
244
    TextureType_UNSIGNED_SHORT_5_6_5 = 33635,
245
    TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819,
246
    TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820
247
};
248
249
//! Values for the Accessor::type field (helper class)
250
class AttribType {
251
public:
252
    enum Value { SCALAR,
253
        VEC2,
254
        VEC3,
255
        VEC4,
256
        MAT2,
257
        MAT3,
258
        MAT4
259
    };
260
261
856
    inline static Value FromString(const char *str) {
262
2.12k
        for (size_t i = 0; i < NUM_VALUES; ++i) {
263
2.09k
            if (strcmp(data<0>::infos[i].name, str) == 0) {
264
830
                return static_cast<Value>(i);
265
830
            }
266
2.09k
        }
267
26
        return SCALAR;
268
856
    }
269
270
0
    inline static const char *ToString(Value type) {
271
0
        return data<0>::infos[static_cast<size_t>(type)].name;
272
0
    }
273
274
0
    inline static unsigned int GetNumComponents(Value type) {
275
0
        return data<0>::infos[static_cast<size_t>(type)].numComponents;
276
0
    }
277
278
private:
279
    static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
280
    struct Info {
281
        const char *name;
282
        unsigned int numComponents;
283
    };
284
285
    template <int N>
286
    struct data {
287
        static const Info infos[NUM_VALUES];
288
    };
289
};
290
291
// must match the order of the AttribTypeTraits::Value enum!
292
template <int N>
293
const AttribType::Info AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
294
    { "SCALAR", 1 },
295
    { "VEC2", 2 },
296
    { "VEC3", 3 },
297
    { "VEC4", 4 },
298
    { "MAT2", 4 },
299
    { "MAT3", 9 },
300
    { "MAT4", 16 }
301
};
302
303
//! Base class for all glTF top-level objects
304
struct Object {
305
    std::string id; //!< The globally unique ID used to reference this object
306
    std::string name; //!< The user-defined name of this object
307
308
    //! Objects marked as special are not exported (used to emulate the binary body buffer)
309
0
    virtual bool IsSpecial() const { return false; }
310
311
9.57k
    Object() = default;
312
8.13k
    virtual ~Object() = default;
313
314
    //! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
315
6.90k
    static const char *TranslateId(Asset & /*r*/, const char *id) { return id; }
316
};
317
318
//
319
// Classes for each glTF top-level object type
320
//
321
322
//! A typed view into a BufferView. A BufferView contains raw binary data.
323
//! An accessor provides a typed view into a BufferView or a subset of a BufferView
324
//! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer.
325
struct Accessor : public Object {
326
    Ref<BufferView> bufferView; //!< The ID of the bufferView. (required)
327
    unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required)
328
    unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
329
    ComponentType componentType; //!< The datatype of components in the attribute. (required)
330
    unsigned int count; //!< The number of attributes referenced by this accessor. (required)
331
    AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
332
    std::vector<double> max; //!< Maximum value of each component in this attribute.
333
    std::vector<double> min; //!< Minimum value of each component in this attribute.
334
335
    unsigned int GetNumComponents();
336
    unsigned int GetBytesPerComponent();
337
    unsigned int GetElementSize();
338
339
    inline uint8_t *GetPointer();
340
341
    template <class T>
342
    bool ExtractData(T *&outData);
343
344
    void WriteData(size_t count, const void *src_buffer, size_t src_stride);
345
346
    //! Helper class to iterate the data
347
    class Indexer {
348
        friend struct Accessor;
349
350
        // 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:
351
        // ../code/glTF2/glTF2Asset.h:392:19: error: private field 'accessor' is not used [-Werror,-Wunused-private-field]
352
    protected:
353
        Accessor &accessor;
354
355
    private:
356
        uint8_t *data;
357
        size_t elemSize, stride;
358
359
        Indexer(Accessor &acc);
360
361
    public:
362
        //! Accesses the i-th value as defined by the accessor
363
        template <class T>
364
        T GetValue(int i);
365
366
        //! Accesses the i-th value as defined by the accessor
367
0
        inline unsigned int GetUInt(int i) {
368
0
            return GetValue<unsigned int>(i);
369
0
        }
370
371
0
        inline bool IsValid() const {
372
0
            return data != nullptr;
373
0
        }
374
    };
375
376
0
    inline Indexer GetIndexer() {
377
0
        return Indexer(*this);
378
0
    }
379
380
936
    Accessor() = default;
381
    void Read(Value &obj, Asset &r);
382
};
383
384
//! A buffer points to binary geometry, animation, or skins.
385
struct Buffer : public Object {
386
    /********************* Types *********************/
387
    enum Type {
388
        Type_arraybuffer,
389
        Type_text
390
    };
391
392
    /// @brief  Descriptor of encoded region in "bufferView".
393
    struct SEncodedRegion {
394
        const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
395
        const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
396
        uint8_t *const DecodedData; ///< Cached encoded data.
397
        const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
398
        const std::string ID; ///< ID of the region.
399
400
        /// @brief Constructor.
401
        /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
402
        /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
403
        /// \param [in] pDecodedData - pointer to decoded data array.
404
        /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
405
        /// \param [in] pID - ID of the region.
406
        SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
407
0
                Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
408
409
        /// Destructor.
410
0
        ~SEncodedRegion() { delete[] DecodedData; }
411
    };
412
413
    /******************* Variables *******************/
414
415
    size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
416
417
    Type type;
418
419
    /// \var EncodedRegion_Current
420
    /// Pointer to currently active encoded region.
421
    /// Why not decoding all regions at once and not to set one buffer with decoded data?
422
    /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded
423
    /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But
424
    /// offset is counted for another regions is encoded.
425
    /// 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:
426
    /// M1_E0, M1_E1, M2_E0, M2_E1.
427
    /// After decoding you'll get:
428
    /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3.
429
    /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like
430
    /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4}
431
    /// but in real life you'll get:
432
    /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4}
433
    /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded.
434
    /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished
435
    /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data.
436
    ///
437
    /// 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
438
    /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory.
439
    SEncodedRegion *EncodedRegion_Current;
440
441
private:
442
    shared_ptr<uint8_t> mData; //!< Pointer to the data
443
    bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
444
    size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0)
445
    /// \var EncodedRegion_List
446
    /// List of encoded regions.
447
    std::list<SEncodedRegion *> EncodedRegion_List;
448
449
    /******************* Functions *******************/
450
451
public:
452
    Buffer();
453
    ~Buffer();
454
455
    void Read(Value &obj, Asset &r);
456
457
    bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
458
459
    /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
460
    /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
461
    /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
462
    /// \param [in] pDecodedData - pointer to decoded data array.
463
    /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
464
    /// \param [in] pID - ID of the region.
465
    void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
466
467
    /// Select current encoded region by ID. \sa EncodedRegion_Current.
468
    /// \param [in] pID - ID of the region.
469
    void EncodedRegion_SetCurrent(const std::string &pID);
470
471
    /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
472
    /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
473
    /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
474
    /// \param [in] pReplace_Data - pointer to array with new data for buffer.
475
    /// \param [in] pReplace_Count - count of bytes in new data.
476
    /// \return true - if successfully replaced, false if input arguments is out of range.
477
    bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count);
478
479
    size_t AppendData(uint8_t *data, size_t length);
480
    void Grow(size_t amount);
481
482
0
    uint8_t *GetPointer() { return mData.get(); }
483
484
4.09k
    void MarkAsSpecial() { mIsSpecial = true; }
485
486
0
    bool IsSpecial() const { return mIsSpecial; }
487
488
0
    std::string GetURI() { return std::string(this->id) + ".bin"; }
489
490
    static const char *TranslateId(Asset &r, const char *id);
491
};
492
493
//! A view into a buffer generally representing a subset of the buffer.
494
struct BufferView : public Object {
495
    Ref<Buffer> buffer; //! The ID of the buffer. (required)
496
    size_t byteOffset; //! The offset into the buffer in bytes. (required)
497
    size_t byteLength; //! The length of the bufferView in bytes. (default: 0)
498
499
    BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
500
501
    void Read(Value &obj, Asset &r);
502
};
503
504
struct Camera : public Object {
505
    enum Type {
506
        Perspective,
507
        Orthographic
508
    };
509
510
    Type type;
511
    struct Perspective {
512
        float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
513
        float yfov; //!<The floating - point vertical field of view in radians. (required)
514
        float zfar; //!<The floating - point distance to the far clipping plane. (required)
515
        float znear; //!< The floating - point distance to the near clipping plane. (required)
516
    };
517
518
    struct Ortographic {
519
        float xmag; //! The floating-point horizontal magnification of the view. (required)
520
        float ymag; //! The floating-point vertical magnification of the view. (required)
521
        float zfar; //! The floating-point distance to the far clipping plane. (required)
522
        float znear; //! The floating-point distance to the near clipping plane. (required)
523
    };
524
    union {
525
        struct Perspective perspective;
526
        struct Ortographic ortographic;
527
    };
528
529
0
    Camera() = default;
530
    void Read(Value &obj, Asset &r);
531
};
532
533
//! Image data used to create a texture.
534
struct Image : public Object {
535
    std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
536
    Ref<BufferView> bufferView;
537
    std::string mimeType;
538
    int width, height;
539
540
public:
541
    Image();
542
    void Read(Value &obj, Asset &r);
543
0
    inline bool HasData() const { return mDataLength > 0; }
544
0
    inline size_t GetDataLength() const { return mDataLength; }
545
0
    inline const uint8_t *GetData() const { return mData.get(); }
546
    inline uint8_t *StealData();
547
    inline void SetData(uint8_t *data, size_t length, Asset &r);
548
549
private:
550
    std::unique_ptr<uint8_t[]> mData;
551
    size_t mDataLength;
552
};
553
554
//! Holds a material property that can be a texture or a color
555
struct TexProperty {
556
    Ref<Texture> texture;
557
    vec4 color;
558
};
559
560
//! The material appearance of a primitive.
561
struct Material : public Object {
562
    //Ref<Sampler> source; //!< The ID of the technique.
563
    //std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values.
564
565
    //! Techniques defined by KHR_materials_common
566
    enum Technique {
567
        Technique_undefined = 0,
568
        Technique_BLINN,
569
        Technique_PHONG,
570
        Technique_LAMBERT,
571
        Technique_CONSTANT
572
    };
573
574
    TexProperty ambient;
575
    TexProperty diffuse;
576
    TexProperty specular;
577
    TexProperty emission;
578
579
    bool doubleSided;
580
    bool transparent;
581
    float transparency;
582
    float shininess;
583
584
    Technique technique;
585
586
146
    Material() { SetDefaults(); }
587
    void Read(Value &obj, Asset &r);
588
    void SetDefaults();
589
};
590
591
//! 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.
592
struct Mesh : public Object {
593
    typedef std::vector<Ref<Accessor>> AccessorList;
594
595
    struct Primitive {
596
        PrimitiveMode mode;
597
598
        struct Attributes {
599
            AccessorList position, normal, texcoord, color, joint, jointmatrix, weight;
600
        } attributes;
601
602
        Ref<Accessor> indices;
603
604
        Ref<Material> material;
605
    };
606
607
    /// \struct SExtension
608
    /// Extension used for mesh.
609
    struct SExtension {
610
        /// \enum EType
611
        /// Type of extension.
612
        enum EType {
613
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
614
            Compression_Open3DGC, ///< Compression of mesh data using Open3DGC algorithm.
615
#endif
616
617
            Unknown
618
        };
619
620
        EType Type; ///< Type of extension.
621
622
        /// \fn SExtension
623
        /// Constructor.
624
        /// \param [in] pType - type of extension.
625
        SExtension(const EType pType) :
626
0
                Type(pType) {}
627
628
0
        virtual ~SExtension() = default;
629
    };
630
631
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
632
633
    /// \struct SCompression_Open3DGC
634
    /// Compression of mesh data using Open3DGC algorithm.
635
    struct SCompression_Open3DGC : public SExtension {
636
        using SExtension::Type;
637
638
        std::string Buffer; ///< ID of "buffer" used for storing compressed data.
639
        size_t Offset; ///< Offset in "bufferView" where compressed data are stored.
640
        size_t Count; ///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type".
641
        bool Binary; ///< If true then "binary" mode is used for coding, if false - "ascii" mode.
642
        size_t IndicesCount; ///< Count of indices in mesh.
643
        size_t VerticesCount; ///< Count of vertices in mesh.
644
        // AttribType::Value Type;///< Is always "SCALAR".
645
        // ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121).
646
647
        /// \fn SCompression_Open3DGC
648
        /// Constructor.
649
        SCompression_Open3DGC() :
650
0
                SExtension(Compression_Open3DGC) {
651
            // empty
652
0
        }
653
654
0
        virtual ~SCompression_Open3DGC() = default;
655
    };
656
#endif
657
658
    std::vector<Primitive> primitives;
659
    std::list<SExtension *> Extension; ///< List of extensions used in mesh.
660
661
1.07k
    Mesh() = default;
662
663
    /// Destructor.
664
850
    ~Mesh() {
665
850
        for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
666
0
            delete *it;
667
0
        };
668
850
    }
669
670
    /// @brief Get mesh data from JSON-object and place them to root asset.
671
    /// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
672
    /// \param [out] pAsset_Root - reference to root asset where data will be stored.
673
    void Read(Value &pJSON_Object, Asset &pAsset_Root);
674
675
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
676
    /// @brief Decode part of "buffer" which encoded with Open3DGC algorithm.
677
    /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
678
    /// \param [out] pAsset_Root - reference to root assed where data will be stored.
679
    void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root);
680
#endif
681
};
682
683
struct Node : public Object {
684
    std::vector<Ref<Node>> children;
685
    std::vector<Ref<Mesh>> meshes;
686
687
    Nullable<mat4> matrix;
688
    Nullable<vec3> translation;
689
    Nullable<vec4> rotation;
690
    Nullable<vec3> scale;
691
692
    Ref<Camera> camera;
693
    Ref<Light> light;
694
695
    std::vector<Ref<Node>> skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
696
    Ref<Skin> skin; //!< The ID of the skin referenced by this node.
697
    std::string jointName; //!< Name used when this node is a joint in a skin.
698
699
    Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
700
701
1.82k
    Node() = default;
702
    void Read(Value &obj, Asset &r);
703
};
704
705
struct Program : public Object {
706
    Program() = default;
707
    void Read(Value &obj, Asset &r);
708
};
709
710
struct Sampler : public Object {
711
    SamplerMagFilter magFilter; //!< The texture magnification filter. (required)
712
    SamplerMinFilter minFilter; //!< The texture minification filter. (required)
713
    SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
714
    SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
715
716
20
    Sampler() = default;
717
    void Read(Value &obj, Asset &r);
718
    void SetDefaults();
719
};
720
721
struct Scene : public Object {
722
    std::vector<Ref<Node>> nodes;
723
724
612
    Scene() = default;
725
    void Read(Value &obj, Asset &r);
726
};
727
728
struct Shader : public Object {
729
    Shader() = default;
730
    void Read(Value &obj, Asset &r);
731
};
732
733
struct Skin : public Object {
734
    Nullable<mat4> bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order.
735
    Ref<Accessor> inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices.
736
    std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
737
    std::string name; //!< The user-defined name of this object.
738
739
0
    Skin() = default;
740
    void Read(Value &obj, Asset &r);
741
};
742
743
struct Technique : public Object {
744
    struct Parameters {
745
    };
746
747
    struct States {
748
    };
749
750
    struct Functions {
751
    };
752
753
    Technique() = default;
754
    void Read(Value &obj, Asset &r);
755
};
756
757
//! A texture and its sampler.
758
struct Texture : public Object {
759
    Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
760
    Ref<Image> source; //!< The ID of the image used by this texture. (required)
761
762
102
    Texture() = default;
763
    void Read(Value &obj, Asset &r);
764
};
765
766
//! A light (from KHR_materials_common extension)
767
struct Light : public Object {
768
    enum Type {
769
        Type_undefined,
770
        Type_ambient,
771
        Type_directional,
772
        Type_point,
773
        Type_spot
774
    };
775
776
    Type type;
777
    vec4 color;
778
    float distance;
779
    float constantAttenuation;
780
    float linearAttenuation;
781
    float quadraticAttenuation;
782
    float falloffAngle;
783
    float falloffExponent;
784
785
0
    Light() = default;
786
    void Read(Value &obj, Asset &r);
787
    void SetDefaults();
788
};
789
790
struct Animation : public Object {
791
    struct AnimSampler {
792
        std::string id; //!< The ID of this sampler.
793
        std::string input; //!< The ID of a parameter in this animation to use as key-frame input.
794
        std::string interpolation; //!< Type of interpolation algorithm to use between key-frames.
795
        std::string output; //!< The ID of a parameter in this animation to use as key-frame output.
796
    };
797
798
    struct AnimChannel {
799
        std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property.
800
801
        struct AnimTarget {
802
            Ref<Node> id; //!< The ID of the node to animate.
803
            std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale").
804
        } target;
805
    };
806
807
    struct AnimParameters {
808
        Ref<Accessor> TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values.
809
        Ref<Accessor> rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors.
810
        Ref<Accessor> scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
811
        Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
812
    };
813
814
    std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
815
    AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
816
    std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
817
818
0
    Animation() = default;
819
    void Read(Value &obj, Asset &r);
820
};
821
822
//! Base class for LazyDict that acts as an interface
823
class LazyDictBase {
824
public:
825
153k
    virtual ~LazyDictBase() = default;
826
827
    virtual void AttachToDocument(Document &doc) = 0;
828
    virtual void DetachFromDocument() = 0;
829
830
#if !defined(ASSIMP_BUILD_NO_EXPORT)
831
    virtual void WriteObjects(AssetWriter &writer) = 0;
832
#endif
833
};
834
835
template <class T>
836
class LazyDict;
837
838
//! (Implemented in glTFAssetWriter.h)
839
template <class T>
840
void WriteLazyDict(LazyDict<T> &d, AssetWriter &w);
841
842
//! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID
843
//! It is the owner the loaded objects, so when it is destroyed it also deletes them
844
template <class T>
845
class LazyDict : public LazyDictBase {
846
    friend class Asset;
847
    friend class AssetWriter;
848
849
    typedef typename std::gltf_unordered_map<std::string, unsigned int> Dict;
850
851
    std::vector<T *> mObjs; //! The read objects
852
    Dict mObjsById; //! The read objects accessible by id
853
    const char *mDictId; //! ID of the dictionary object
854
    const char *mExtId; //! ID of the extension defining the dictionary
855
    Value *mDict; //! JSON dictionary object
856
    Asset &mAsset; //! The asset instance
857
858
    void AttachToDocument(Document &doc);
859
    void DetachFromDocument();
860
861
#if !defined(ASSIMP_BUILD_NO_EXPORT)
862
0
    void WriteObjects(AssetWriter &writer) { WriteLazyDict<T>(*this, writer); }
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::WriteObjects(glTF::AssetWriter&)
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::WriteObjects(glTF::AssetWriter&)
863
#endif
864
865
    Ref<T> Add(T *obj);
866
867
public:
868
    LazyDict(Asset &asset, const char *dictId, const char *extId = nullptr);
869
    ~LazyDict();
870
871
    Ref<T> Get(const char *id);
872
    Ref<T> Get(unsigned int i);
873
0
    Ref<T> Get(const std::string &pID) { return Get(pID.c_str()); }
874
875
    Ref<T> Create(const char *id);
876
0
    Ref<T> Create(const std::string &id) { return Create(id.c_str()); }
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::Create(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
877
878
3.12k
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
glTF::LazyDict<glTF::Material>::Size() const
Line
Count
Source
878
503
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
glTF::LazyDict<glTF::Mesh>::Size() const
Line
Count
Source
878
607
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
glTF::LazyDict<glTF::Camera>::Size() const
Line
Count
Source
878
503
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
glTF::LazyDict<glTF::Light>::Size() const
Line
Count
Source
878
503
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
glTF::LazyDict<glTF::Image>::Size() const
Line
Count
Source
878
1.00k
    inline unsigned int Size() const { return unsigned(mObjs.size()); }
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Size() const
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Size() const
879
880
114
    inline T &operator[](size_t i) { return *mObjs[i]; }
glTF::LazyDict<glTF::Material>::operator[](unsigned long)
Line
Count
Source
880
10
    inline T &operator[](size_t i) { return *mObjs[i]; }
glTF::LazyDict<glTF::Mesh>::operator[](unsigned long)
Line
Count
Source
880
104
    inline T &operator[](size_t i) { return *mObjs[i]; }
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::operator[](unsigned long)
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::operator[](unsigned long)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::operator[](unsigned long)
881
};
882
883
struct AssetMetadata {
884
    std::string copyright; //!< A copyright message suitable for display to credit the content creator.
885
    std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
886
    bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false)
887
888
    struct {
889
        std::string api; //!< Specifies the target rendering API (default: "WebGL")
890
        std::string version; //!< Specifies the target rendering API (default: "1.0.3")
891
    } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
892
893
    std::string version; //!< The glTF format version (should be 1.0)
894
895
    void Read(Document &doc);
896
897
    AssetMetadata() :
898
10.9k
            premultipliedAlpha(false) {
899
10.9k
    }
900
901
7.78k
    operator bool() const { return version.size() && version[0] == '1'; }
902
};
903
904
//
905
// glTF Asset class
906
//
907
908
//! Root object for a glTF asset
909
class Asset {
910
    using IdMap = std::gltf_unordered_map<std::string, int>;
911
912
    template <class T>
913
    friend class LazyDict;
914
    friend struct Buffer; // To access OpenFile
915
    friend class AssetWriter;
916
917
private:
918
    IOSystem *mIOSystem;
919
920
    std::string mCurrentAssetDir;
921
922
    size_t mSceneLength;
923
    size_t mBodyOffset, mBodyLength;
924
925
    std::vector<LazyDictBase *> mDicts;
926
927
    IdMap mUsedIds;
928
929
    Ref<Buffer> mBodyBuffer;
930
931
    Asset(Asset &);
932
    Asset &operator=(const Asset &);
933
934
public:
935
    //! Keeps info about the enabled extensions
936
    struct Extensions {
937
        bool KHR_binary_glTF;
938
        bool KHR_materials_common;
939
940
    } extensionsUsed;
941
942
    AssetMetadata asset;
943
944
    // Dictionaries for each type of object
945
946
    LazyDict<Accessor> accessors;
947
    LazyDict<Animation> animations;
948
    LazyDict<Buffer> buffers;
949
    LazyDict<BufferView> bufferViews;
950
    LazyDict<Camera> cameras;
951
    LazyDict<Image> images;
952
    LazyDict<Material> materials;
953
    LazyDict<Mesh> meshes;
954
    LazyDict<Node> nodes;
955
    LazyDict<Sampler> samplers;
956
    LazyDict<Scene> scenes;
957
    LazyDict<Skin> skins;
958
    LazyDict<Texture> textures;
959
960
    LazyDict<Light> lights; // KHR_materials_common ext
961
962
    Ref<Scene> scene;
963
964
public:
965
    Asset(IOSystem *io = nullptr) :
966
10.9k
            mIOSystem(io),
967
10.9k
            asset(),
968
10.9k
            accessors(*this, "accessors"),
969
10.9k
            animations(*this, "animations"),
970
10.9k
            buffers(*this, "buffers"),
971
10.9k
            bufferViews(*this, "bufferViews"),
972
10.9k
            cameras(*this, "cameras"),
973
10.9k
            images(*this, "images"),
974
10.9k
            materials(*this, "materials"),
975
10.9k
            meshes(*this, "meshes"),
976
10.9k
            nodes(*this, "nodes"),
977
10.9k
            samplers(*this, "samplers"),
978
10.9k
            scenes(*this, "scenes"),
979
10.9k
            skins(*this, "skins"),
980
10.9k
            textures(*this, "textures"),
981
10.9k
            lights(*this, "lights", "KHR_materials_common") {
982
10.9k
        memset(&extensionsUsed, 0, sizeof(extensionsUsed));
983
10.9k
    }
984
985
    //! Main function
986
    void Load(const std::string &file, bool isBinary = false);
987
988
    //! Enables the "KHR_binary_glTF" extension on the asset
989
    void SetAsBinary();
990
991
    //! Search for an available name, starting from the given strings
992
    std::string FindUniqueID(const std::string &str, const char *suffix);
993
994
0
    Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
995
996
private:
997
    void ReadBinaryHeader(IOStream &stream);
998
999
    void ReadExtensionsUsed(Document &doc);
1000
1001
    IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
1002
};
1003
1004
} // namespace glTF
1005
1006
// Include the implementation of the methods
1007
#include "glTFAsset.inl"
1008
1009
#endif // GLTFASSET_H_INC