Coverage Report

Created: 2025-08-26 06:41

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