Coverage Report

Created: 2025-08-28 06:38

/src/assimp/code/AssetLib/glTF/glTFAsset.inl
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
#include <assimp/MemoryIOWrapper.h>
43
#include <assimp/StringUtils.h>
44
#include <iomanip>
45
46
// Header files, Assimp
47
#include <assimp/DefaultLogger.hpp>
48
#include <assimp/Base64.hpp>
49
50
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
51
// Header files, Open3DGC.
52
#include <Open3DGC/o3dgcSC3DMCDecoder.h>
53
#endif
54
55
using namespace Assimp;
56
57
namespace glTF {
58
using namespace glTFCommon;
59
60
#if _MSC_VER
61
#pragma warning(push)
62
#pragma warning(disable : 4706)
63
#endif // _MSC_VER
64
65
//
66
// LazyDict methods
67
//
68
69
template <class T>
70
inline LazyDict<T>::LazyDict(Asset &asset, const char *dictId, const char *extId) :
71
546
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
546
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
546
}
glTF::LazyDict<glTF::Accessor>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Animation>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Buffer>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::BufferView>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Camera>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Image>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Material>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Mesh>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Node>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Sampler>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Scene>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Skin>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Texture>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
glTF::LazyDict<glTF::Light>::LazyDict(glTF::Asset&, char const*, char const*)
Line
Count
Source
71
39
        mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) {
72
39
    asset.mDicts.push_back(this); // register to the list of dictionaries
73
39
}
74
75
template <class T>
76
546
inline LazyDict<T>::~LazyDict() {
77
546
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
546
}
glTF::LazyDict<glTF::Light>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Texture>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Skin>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Scene>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Sampler>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Node>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Mesh>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Material>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Image>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Camera>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::BufferView>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Buffer>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Animation>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
glTF::LazyDict<glTF::Accessor>::~LazyDict()
Line
Count
Source
76
39
inline LazyDict<T>::~LazyDict() {
77
39
    for (size_t i = 0; i < mObjs.size(); ++i) {
78
0
        delete mObjs[i];
79
0
    }
80
39
}
81
82
template <class T>
83
0
inline void LazyDict<T>::AttachToDocument(Document &doc) {
84
0
    Value *container = nullptr;
85
86
0
    if (mExtId) {
87
0
        if (Value *exts = FindObject(doc, "extensions")) {
88
0
            container = FindObject(*exts, mExtId);
89
0
        }
90
0
    } else {
91
0
        container = &doc;
92
0
    }
93
94
0
    if (container) {
95
0
        mDict = FindObject(*container, mDictId);
96
0
    }
97
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
98
99
template <class T>
100
0
inline void LazyDict<T>::DetachFromDocument() {
101
0
    mDict = nullptr;
102
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::DetachFromDocument()
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::DetachFromDocument()
103
104
template <class T>
105
0
Ref<T> LazyDict<T>::Get(unsigned int i) {
106
0
    return Ref<T>(mObjs, i);
107
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Get(unsigned int)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Get(unsigned int)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Get(unsigned int)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Get(unsigned int)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Get(unsigned int)
108
109
template <class T>
110
0
Ref<T> LazyDict<T>::Get(const char *id) {
111
0
    id = T::TranslateId(mAsset, id);
112
113
0
    typename Dict::iterator it = mObjsById.find(id);
114
0
    if (it != mObjsById.end()) { // already created?
115
0
        return Ref<T>(mObjs, it->second);
116
0
    }
117
118
    // read it from the JSON object
119
0
    if (!mDict) {
120
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
121
0
    }
122
123
0
    Value::MemberIterator obj = mDict->FindMember(id);
124
0
    if (obj == mDict->MemberEnd()) {
125
0
        throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\"");
126
0
    }
127
0
    if (!obj->value.IsObject()) {
128
0
        throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object");
129
0
    }
130
131
    // create an instance of the given type
132
0
    T *inst = new T();
133
0
    inst->id = id;
134
0
    ReadMember(obj->value, "name", inst->name);
135
0
    inst->Read(obj->value, mAsset);
136
0
    return Add(inst);
137
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::Get(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Get(char const*)
138
139
template <class T>
140
0
Ref<T> LazyDict<T>::Add(T *obj) {
141
0
    unsigned int idx = unsigned(mObjs.size());
142
0
    mObjs.push_back(obj);
143
0
    mObjsById[obj->id] = idx;
144
0
    mAsset.mUsedIds[obj->id] = true;
145
0
    return Ref<T>(mObjs, idx);
146
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Add(glTF::Buffer*)
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Add(glTF::BufferView*)
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Add(glTF::Accessor*)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Add(glTF::Image*)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Add(glTF::Sampler*)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Add(glTF::Texture*)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Add(glTF::Material*)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Add(glTF::Mesh*)
Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::Add(glTF::Camera*)
Unexecuted instantiation: glTF::LazyDict<glTF::Light>::Add(glTF::Light*)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Add(glTF::Node*)
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::Add(glTF::Skin*)
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Add(glTF::Scene*)
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::Add(glTF::Animation*)
147
148
template <class T>
149
0
Ref<T> LazyDict<T>::Create(const char *id) {
150
0
    Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
151
0
    if (it != mAsset.mUsedIds.end()) {
152
0
        throw DeadlyImportError("GLTF: two objects with the same ID exist");
153
0
    }
154
0
    T *inst = new T();
155
0
    inst->id = id;
156
0
    return Add(inst);
157
0
}
Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Create(char const*)
Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::Create(char const*)
158
159
//
160
// glTF dictionary objects methods
161
//
162
163
inline Buffer::Buffer() :
164
0
        byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) {}
165
166
0
inline Buffer::~Buffer() {
167
0
    for (SEncodedRegion *reg : EncodedRegion_List)
168
0
        delete reg;
169
0
}
170
171
0
inline const char *Buffer::TranslateId(Asset &r, const char *id) {
172
    // Compatibility with old spec
173
0
    if (r.extensionsUsed.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) {
174
0
        return "binary_glTF";
175
0
    }
176
177
0
    return id;
178
0
}
179
180
0
inline void Buffer::Read(Value &obj, Asset &r) {
181
0
    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
182
0
    byteLength = statedLength;
183
184
0
    Value *it = FindString(obj, "uri");
185
0
    if (!it) {
186
0
        if (statedLength > 0) {
187
0
            throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
188
0
        }
189
0
        return;
190
0
    }
191
192
0
    const char *uri = it->GetString();
193
194
0
    glTFCommon::Util::DataURI dataURI;
195
0
    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
196
0
        if (dataURI.base64) {
197
0
            uint8_t *data = nullptr;
198
0
            this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data);
199
0
            this->mData.reset(data, std::default_delete<uint8_t[]>());
200
201
0
            if (statedLength > 0 && this->byteLength != statedLength) {
202
0
                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
203
0
                        " bytes, but found ", ai_to_string(dataURI.dataLength));
204
0
            }
205
0
        } else { // assume raw data
206
0
            if (statedLength != dataURI.dataLength) {
207
0
                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
208
0
                        " bytes, but found ", ai_to_string(dataURI.dataLength));
209
0
            }
210
211
0
            this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
212
0
            memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
213
0
        }
214
0
    } else { // Local file
215
0
        if (byteLength > 0) {
216
0
            std::string dir = !r.mCurrentAssetDir.empty() ? (
217
0
                                                                    r.mCurrentAssetDir.back() == '/' ?
218
0
                                                                            r.mCurrentAssetDir :
219
0
                                                                            r.mCurrentAssetDir + '/') :
220
0
                                                            "";
221
222
0
            IOStream *file = r.OpenFile(dir + uri, "rb");
223
0
            if (file) {
224
0
                bool ok = LoadFromStream(*file, byteLength);
225
0
                delete file;
226
227
0
                if (!ok)
228
0
                    throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
229
0
            } else {
230
0
                throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
231
0
            }
232
0
        }
233
0
    }
234
0
}
235
236
0
inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
237
0
    byteLength = length ? length : stream.FileSize();
238
239
0
    if (baseOffset) {
240
0
        stream.Seek(baseOffset, aiOrigin_SET);
241
0
    }
242
243
0
    mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
244
245
0
    if (stream.Read(mData.get(), byteLength, 1) != 1) {
246
0
        return false;
247
0
    }
248
0
    return true;
249
0
}
250
251
0
inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) {
252
    // Check pointer to data
253
0
    if (pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
254
255
    // Check offset
256
0
    if (pOffset > byteLength) {
257
0
        const uint8_t val_size = 32;
258
259
0
        char val[val_size];
260
261
0
        ai_snprintf(val, val_size, AI_SIZEFMT, pOffset);
262
0
        throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region.");
263
0
    }
264
265
    // Check length
266
0
    if ((pOffset + pEncodedData_Length) > byteLength) {
267
0
        const uint8_t val_size = 64;
268
269
0
        char val[val_size];
270
271
0
        ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length);
272
0
        throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range.");
273
0
    }
274
275
    // Add new region
276
0
    EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
277
    // And set new value for "byteLength"
278
0
    byteLength += (pDecodedData_Length - pEncodedData_Length);
279
0
}
280
281
0
inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
282
0
    if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return;
283
284
0
    for (SEncodedRegion *reg : EncodedRegion_List) {
285
0
        if (reg->ID == pID) {
286
0
            EncodedRegion_Current = reg;
287
288
0
            return;
289
0
        }
290
0
    }
291
292
0
    throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found.");
293
0
}
294
295
0
inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
296
0
    const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
297
298
0
    uint8_t *new_data;
299
300
0
    if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false;
301
302
0
    new_data = new uint8_t[new_data_size];
303
    // Copy data which place before replacing part.
304
0
    memcpy(new_data, mData.get(), pBufferData_Offset);
305
    // Copy new data.
306
0
    memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
307
    // Copy data which place after replacing part.
308
0
    memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
309
    // Apply new data
310
0
    mData.reset(new_data, std::default_delete<uint8_t[]>());
311
0
    byteLength = new_data_size;
312
313
0
    return true;
314
0
}
315
316
0
inline size_t Buffer::AppendData(uint8_t *data, size_t length) {
317
0
    size_t offset = this->byteLength;
318
0
    Grow(length);
319
0
    memcpy(mData.get() + offset, data, length);
320
0
    return offset;
321
0
}
322
323
0
inline void Buffer::Grow(size_t amount) {
324
0
    if (amount <= 0) return;
325
0
    if (capacity >= byteLength + amount) {
326
0
        byteLength += amount;
327
0
        return;
328
0
    }
329
330
    // Shift operation is standard way to divide integer by 2, it doesn't cast it to float back and forth, also works for odd numbers,
331
    // originally it would look like: static_cast<size_t>(capacity * 1.5f)
332
0
    capacity = std::max(capacity + (capacity >> 1), byteLength + amount);
333
334
0
    uint8_t *b = new uint8_t[capacity];
335
0
    if (mData) memcpy(b, mData.get(), byteLength);
336
0
    mData.reset(b, std::default_delete<uint8_t[]>());
337
0
    byteLength += amount;
338
0
}
339
340
//
341
// struct BufferView
342
//
343
344
0
inline void BufferView::Read(Value &obj, Asset &r) {
345
0
    const char *bufferId = MemberOrDefault<const char *>(obj, "buffer", 0);
346
0
    if (bufferId) {
347
0
        buffer = r.buffers.Get(bufferId);
348
0
    }
349
350
0
    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
351
0
    byteLength = MemberOrDefault(obj, "byteLength", 0u);
352
0
}
353
354
//
355
// struct Accessor
356
//
357
358
0
inline void Accessor::Read(Value &obj, Asset &r) {
359
0
    const char *bufferViewId = MemberOrDefault<const char *>(obj, "bufferView", 0);
360
0
    if (bufferViewId) {
361
0
        bufferView = r.bufferViews.Get(bufferViewId);
362
0
    }
363
364
0
    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
365
0
    byteStride = MemberOrDefault(obj, "byteStride", 0u);
366
0
    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
367
0
    count = MemberOrDefault(obj, "count", 0u);
368
369
0
    const char *typestr;
370
0
    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
371
0
}
372
373
0
inline unsigned int Accessor::GetNumComponents() {
374
0
    return AttribType::GetNumComponents(type);
375
0
}
376
377
0
inline unsigned int Accessor::GetBytesPerComponent() {
378
0
    return int(ComponentTypeSize(componentType));
379
0
}
380
381
0
inline unsigned int Accessor::GetElementSize() {
382
0
    return GetNumComponents() * GetBytesPerComponent();
383
0
}
384
385
0
inline uint8_t *Accessor::GetPointer() {
386
0
    if (!bufferView || !bufferView->buffer) return nullptr;
387
0
    uint8_t *basePtr = bufferView->buffer->GetPointer();
388
0
    if (!basePtr) return nullptr;
389
390
0
    size_t offset = byteOffset + bufferView->byteOffset;
391
392
    // Check if region is encoded.
393
0
    if (bufferView->buffer->EncodedRegion_Current != nullptr) {
394
0
        const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
395
0
        const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
396
397
0
        if ((offset >= begin) && (offset < end))
398
0
            return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
399
0
    }
400
401
0
    return basePtr + offset;
402
0
}
403
404
namespace {
405
inline void CopyData(size_t count,
406
        const uint8_t *src, size_t src_stride,
407
0
        uint8_t *dst, size_t dst_stride) {
408
0
    if (src_stride == dst_stride) {
409
0
        memcpy(dst, src, count * src_stride);
410
0
    } else {
411
0
        size_t sz = std::min(src_stride, dst_stride);
412
0
        for (size_t i = 0; i < count; ++i) {
413
0
            memcpy(dst, src, sz);
414
0
            if (sz < dst_stride) {
415
0
                memset(dst + sz, 0, dst_stride - sz);
416
0
            }
417
0
            src += src_stride;
418
0
            dst += dst_stride;
419
0
        }
420
0
    }
421
0
}
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long)
422
} // namespace
423
424
template <class T>
425
0
bool Accessor::ExtractData(T *&outData) {
426
0
    uint8_t *data = GetPointer();
427
0
    if (!data) return false;
428
429
0
    const size_t elemSize = GetElementSize();
430
0
    const size_t totalSize = elemSize * count;
431
432
0
    const size_t stride = byteStride ? byteStride : elemSize;
433
434
0
    const size_t targetElemSize = sizeof(T);
435
0
    ai_assert(elemSize <= targetElemSize);
436
437
0
    ai_assert(count * stride <= bufferView->byteLength);
438
439
0
    outData = new T[count];
440
0
    if (stride == elemSize && targetElemSize == elemSize) {
441
0
        memcpy(outData, data, totalSize);
442
0
    } else {
443
0
        for (size_t i = 0; i < count; ++i) {
444
0
            memcpy(outData + i, data + i * stride, elemSize);
445
0
        }
446
0
    }
447
448
0
    return true;
449
0
}
450
451
0
inline void Accessor::WriteData(size_t cnt, const void *src_buffer, size_t src_stride) {
452
0
    uint8_t *buffer_ptr = bufferView->buffer->GetPointer();
453
0
    size_t offset = byteOffset + bufferView->byteOffset;
454
455
0
    size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
456
457
0
    const uint8_t *src = reinterpret_cast<const uint8_t *>(src_buffer);
458
0
    uint8_t *dst = reinterpret_cast<uint8_t *>(buffer_ptr + offset);
459
460
0
    ai_assert(dst + count * dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
461
0
    CopyData(cnt, src, src_stride, dst, dst_stride);
462
0
}
463
464
inline Accessor::Indexer::Indexer(Accessor &acc) :
465
0
        accessor(acc), data(acc.GetPointer()), elemSize(acc.GetElementSize()), stride(acc.byteStride ? acc.byteStride : elemSize) {
466
0
}
467
468
//! Accesses the i-th value as defined by the accessor
469
template <class T>
470
0
T Accessor::Indexer::GetValue(int i) {
471
0
    ai_assert(data);
472
0
    ai_assert(i * stride < accessor.bufferView->byteLength);
473
0
    T value = T();
474
0
    memcpy(&value, data + i * stride, elemSize);
475
    //value >>= 8 * (sizeof(T) - elemSize);
476
0
    return value;
477
0
}
478
479
inline Image::Image() :
480
0
        width(0), height(0), mDataLength(0) {
481
0
}
482
483
0
inline void Image::Read(Value &obj, Asset &r) {
484
    // Check for extensions first (to detect binary embedded data)
485
0
    if (Value *extensions = FindObject(obj, "extensions")) {
486
0
        if (r.extensionsUsed.KHR_binary_glTF) {
487
0
            if (Value *ext = FindObject(*extensions, "KHR_binary_glTF")) {
488
489
0
                width = MemberOrDefault(*ext, "width", 0);
490
0
                height = MemberOrDefault(*ext, "height", 0);
491
492
0
                ReadMember(*ext, "mimeType", mimeType);
493
494
0
                const char *bufferViewId;
495
0
                if (ReadMember(*ext, "bufferView", bufferViewId)) {
496
0
                    Ref<BufferView> bv = r.bufferViews.Get(bufferViewId);
497
0
                    if (bv) {
498
0
                        mDataLength = bv->byteLength;
499
0
                        mData.reset(new uint8_t[mDataLength]);
500
0
                        memcpy(mData.get(), bv->buffer->GetPointer() + bv->byteOffset, mDataLength);
501
0
                    }
502
0
                }
503
0
            }
504
0
        }
505
0
    }
506
507
0
    if (!mDataLength) {
508
0
        Value *curUri = FindString(obj, "uri");
509
0
        if (nullptr != curUri) {
510
0
            const char *uristr = curUri->GetString();
511
512
0
            glTFCommon::Util::DataURI dataURI;
513
0
            if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
514
0
                mimeType = dataURI.mediaType;
515
0
                if (dataURI.base64) {
516
0
                    uint8_t *ptr = nullptr;
517
0
                    mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr);
518
0
                    mData.reset(ptr);
519
0
                }
520
0
            } else {
521
0
                this->uri = uristr;
522
0
            }
523
0
        }
524
0
    }
525
0
}
526
527
0
inline uint8_t *Image::StealData() {
528
0
    mDataLength = 0;
529
0
    return mData.release();
530
0
}
531
532
0
inline void Image::SetData(uint8_t *data, size_t length, Asset &r) {
533
0
    Ref<Buffer> b = r.GetBodyBuffer();
534
0
    if (b) { // binary file: append to body
535
0
        std::string bvId = r.FindUniqueID(this->id, "imgdata");
536
0
        bufferView = r.bufferViews.Create(bvId);
537
538
0
        bufferView->buffer = b;
539
0
        bufferView->byteLength = length;
540
0
        bufferView->byteOffset = b->AppendData(data, length);
541
0
    } else { // text file: will be stored as a data uri
542
0
        uint8_t *temp = new uint8_t[length];
543
0
        memcpy(temp, data, length);
544
0
        this->mData.reset(temp);
545
0
        this->mDataLength = length;
546
0
    }
547
0
}
548
549
0
inline void Sampler::Read(Value &obj, Asset & /*r*/) {
550
0
    SetDefaults();
551
552
0
    ReadMember(obj, "magFilter", magFilter);
553
0
    ReadMember(obj, "minFilter", minFilter);
554
0
    ReadMember(obj, "wrapS", wrapS);
555
0
    ReadMember(obj, "wrapT", wrapT);
556
0
}
557
558
0
inline void Sampler::SetDefaults() {
559
0
    magFilter = SamplerMagFilter_Linear;
560
0
    minFilter = SamplerMinFilter_Linear;
561
0
    wrapS = SamplerWrap_Repeat;
562
0
    wrapT = SamplerWrap_Repeat;
563
0
}
564
565
0
inline void Texture::Read(Value &obj, Asset &r) {
566
0
    const char *sourcestr;
567
0
    if (ReadMember(obj, "source", sourcestr)) {
568
0
        source = r.images.Get(sourcestr);
569
0
    }
570
571
0
    const char *samplerstr;
572
0
    if (ReadMember(obj, "sampler", samplerstr)) {
573
0
        sampler = r.samplers.Get(samplerstr);
574
0
    }
575
0
}
576
577
namespace {
578
0
inline void ReadMaterialProperty(Asset &r, Value &vals, const char *propName, TexProperty &out) {
579
0
    if (Value *prop = FindMember(vals, propName)) {
580
0
        if (prop->IsString()) {
581
0
            out.texture = r.textures.Get(prop->GetString());
582
0
        } else {
583
0
            ReadValue(*prop, out.color);
584
0
        }
585
0
    }
586
0
}
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::ReadMaterialProperty(glTF::Asset&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, glTF::TexProperty&)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::ReadMaterialProperty(glTF::Asset&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, glTF::TexProperty&)
587
} // namespace
588
589
0
inline void Material::Read(Value &material, Asset &r) {
590
0
    SetDefaults();
591
592
0
    if (Value *values = FindObject(material, "values")) {
593
0
        ReadMaterialProperty(r, *values, "ambient", this->ambient);
594
0
        ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
595
0
        ReadMaterialProperty(r, *values, "specular", this->specular);
596
597
0
        ReadMember(*values, "transparency", transparency);
598
0
        ReadMember(*values, "shininess", shininess);
599
0
    }
600
601
0
    if (Value *extensions = FindObject(material, "extensions")) {
602
0
        if (r.extensionsUsed.KHR_materials_common) {
603
0
            if (Value *ext = FindObject(*extensions, "KHR_materials_common")) {
604
0
                if (Value *tnq = FindString(*ext, "technique")) {
605
0
                    const char *t = tnq->GetString();
606
0
                    if (strcmp(t, "BLINN") == 0)
607
0
                        technique = Technique_BLINN;
608
0
                    else if (strcmp(t, "PHONG") == 0)
609
0
                        technique = Technique_PHONG;
610
0
                    else if (strcmp(t, "LAMBERT") == 0)
611
0
                        technique = Technique_LAMBERT;
612
0
                    else if (strcmp(t, "CONSTANT") == 0)
613
0
                        technique = Technique_CONSTANT;
614
0
                }
615
616
0
                if (Value *values = FindObject(*ext, "values")) {
617
0
                    ReadMaterialProperty(r, *values, "ambient", this->ambient);
618
0
                    ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
619
0
                    ReadMaterialProperty(r, *values, "specular", this->specular);
620
621
0
                    ReadMember(*values, "doubleSided", doubleSided);
622
0
                    ReadMember(*values, "transparent", transparent);
623
0
                    ReadMember(*values, "transparency", transparency);
624
0
                    ReadMember(*values, "shininess", shininess);
625
0
                }
626
0
            }
627
0
        }
628
0
    }
629
0
}
630
631
namespace {
632
0
void SetVector(vec4 &v, float x, float y, float z, float w) {
633
0
    v[0] = x;
634
0
    v[1] = y;
635
0
    v[2] = z;
636
0
    v[3] = w;
637
0
}
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::SetVector(float (&) [4], float, float, float, float)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::SetVector(float (&) [4], float, float, float, float)
638
} // namespace
639
640
0
inline void Material::SetDefaults() {
641
0
    SetVector(ambient.color, 0, 0, 0, 1);
642
0
    SetVector(diffuse.color, 0, 0, 0, 1);
643
0
    SetVector(specular.color, 0, 0, 0, 1);
644
0
    SetVector(emission.color, 0, 0, 0, 1);
645
646
0
    doubleSided = false;
647
0
    transparent = false;
648
0
    transparency = 1.0;
649
0
    shininess = 0.0;
650
651
0
    technique = Technique_undefined;
652
0
}
653
654
namespace {
655
656
template <int N>
657
0
inline int Compare(const char *attr, const char (&str)[N]) {
658
0
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
659
0
}
Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<9>(char const*, char const (&) [9])
Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<7>(char const*, char const (&) [7])
Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<9>(char const*, char const (&) [9])
Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<7>(char const*, char const (&) [7])
Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
660
661
0
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
662
0
    if ((pos = Compare(attr, "POSITION"))) {
663
0
        v = &(p.attributes.position);
664
0
    } else if ((pos = Compare(attr, "NORMAL"))) {
665
0
        v = &(p.attributes.normal);
666
0
    } else if ((pos = Compare(attr, "TEXCOORD"))) {
667
0
        v = &(p.attributes.texcoord);
668
0
    } else if ((pos = Compare(attr, "COLOR"))) {
669
0
        v = &(p.attributes.color);
670
0
    } else if ((pos = Compare(attr, "JOINT"))) {
671
0
        v = &(p.attributes.joint);
672
0
    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
673
0
        v = &(p.attributes.jointmatrix);
674
0
    } else if ((pos = Compare(attr, "WEIGHT"))) {
675
0
        v = &(p.attributes.weight);
676
0
    } else
677
0
        return false;
678
0
    return true;
679
0
}
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::GetAttribVector(glTF::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >*&, int&)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::GetAttribVector(glTF::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >*&, int&)
680
} // namespace
681
682
0
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
683
    /****************** Mesh primitives ******************/
684
0
    Value *curPrimitives = FindArray(pJSON_Object, "primitives");
685
0
    if (nullptr != curPrimitives) {
686
0
        this->primitives.resize(curPrimitives->Size());
687
0
        for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
688
0
            Value &primitive = (*curPrimitives)[i];
689
690
0
            Primitive &prim = this->primitives[i];
691
0
            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
692
693
0
            if (Value *attrs = FindObject(primitive, "attributes")) {
694
0
                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
695
0
                    if (!it->value.IsString()) continue;
696
0
                    const char *attr = it->name.GetString();
697
                    // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
698
                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
699
700
0
                    int undPos = 0;
701
0
                    Mesh::AccessorList *vec = nullptr;
702
0
                    if (GetAttribVector(prim, attr, vec, undPos)) {
703
0
                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
704
0
                        if ((*vec).size() <= idx) (*vec).resize(idx + 1);
705
0
                        (*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
706
0
                    }
707
0
                }
708
0
            }
709
710
0
            if (Value *indices = FindString(primitive, "indices")) {
711
0
                prim.indices = pAsset_Root.accessors.Get(indices->GetString());
712
0
            }
713
714
0
            if (Value *material = FindString(primitive, "material")) {
715
0
                prim.material = pAsset_Root.materials.Get(material->GetString());
716
0
            }
717
0
        }
718
0
    }
719
720
    /****************** Mesh extensions ******************/
721
0
    Value *json_extensions = FindObject(pJSON_Object, "extensions");
722
723
0
    if (json_extensions == nullptr) goto mr_skip_extensions;
724
725
0
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
726
0
    for (Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) {
727
0
        if (it_memb->name.GetString() == std::string("Open3DGC-compression")) {
728
            // Search for compressed data.
729
            // Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
730
            // new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
731
0
            Value *comp_data = FindObject(it_memb->value, "compressedData");
732
733
0
            if (comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
734
735
0
            ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data.");
736
737
/************** Read data from JSON-document **************/
738
0
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut)                                   \
739
0
    if (!ReadMember(*comp_data, pFieldName, pOut)) {                                        \
740
0
        throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
741
0
    }
742
743
0
            const char *mode_str;
744
0
            const char *type_str;
745
0
            ComponentType component_type;
746
0
            SCompression_Open3DGC *ext_o3dgc = new SCompression_Open3DGC;
747
748
0
            MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
749
0
            MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
750
0
            MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
751
0
            MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
752
0
            MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
753
0
            MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
754
0
            MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
755
0
            MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
756
757
0
#undef MESH_READ_COMPRESSEDDATA_MEMBER
758
759
            // Check some values
760
0
            if (strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
761
0
            if (component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
762
763
            // Set read/write data mode.
764
0
            if (strcmp(mode_str, "binary") == 0)
765
0
                ext_o3dgc->Binary = true;
766
0
            else if (strcmp(mode_str, "ascii") == 0)
767
0
                ext_o3dgc->Binary = false;
768
0
            else
769
0
                throw DeadlyImportError("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"", mode_str, "\".");
770
771
            /************************ Decoding ************************/
772
0
            Decode_O3DGC(*ext_o3dgc, pAsset_Root);
773
0
            Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
774
0
        } // if(it_memb->name.GetString() == "Open3DGC-compression")
775
0
        else {
776
0
            throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
777
0
        }
778
0
    } // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
779
0
#endif
780
781
0
mr_skip_extensions:
782
783
0
    return; // After label some operators must be present.
784
0
}
785
786
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
787
0
inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root) {
788
0
    typedef unsigned short IndicesType; ///< \sa glTFExporter::ExportMeshes.
789
790
0
    o3dgc::SC3DMCDecoder<IndicesType> decoder;
791
0
    o3dgc::IndexedFaceSet<IndicesType> ifs;
792
0
    o3dgc::BinaryStream bstream;
793
0
    uint8_t *decoded_data;
794
0
    size_t decoded_data_size = 0;
795
0
    Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
796
797
    // Read data from buffer and place it in BinaryStream for decoder.
798
    // Just "Count" because always is used type equivalent to uint8_t.
799
0
    bstream.LoadFromBuffer(&buf->GetPointer()[pCompression_Open3DGC.Offset], static_cast<unsigned long>(pCompression_Open3DGC.Count));
800
801
    // After decoding header we can get size of primitives.
802
0
    if (decoder.DecodeHeader(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC header.");
803
804
    /****************** Get sizes of arrays and check sizes ******************/
805
    // Note. See "Limitations for meshes when using Open3DGC-compression".
806
807
    // Indices
808
0
    size_t size_coordindex = ifs.GetNCoordIndex() * 3; // See float attributes note.
809
810
0
    if (primitives[0].indices->count != size_coordindex)
811
0
        throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (", ai_to_string(size_coordindex),
812
0
                ") not equal to uncompressed (", ai_to_string(primitives[0].indices->count), ").");
813
814
0
    size_coordindex *= sizeof(IndicesType);
815
    // Coordinates
816
0
    size_t size_coord = ifs.GetNCoord(); // See float attributes note.
817
818
0
    if (primitives[0].attributes.position[0]->count != size_coord)
819
0
        throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (", ai_to_string(size_coord),
820
0
                ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.position[0]->count), ").");
821
822
0
    size_coord *= 3 * sizeof(float);
823
    // Normals
824
0
    size_t size_normal = ifs.GetNNormal(); // See float attributes note.
825
826
0
    if (primitives[0].attributes.normal[0]->count != size_normal)
827
0
        throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (", ai_to_string(size_normal),
828
0
                ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.normal[0]->count), ").");
829
830
0
    size_normal *= 3 * sizeof(float);
831
    // Additional attributes.
832
0
    std::vector<size_t> size_floatattr;
833
0
    std::vector<size_t> size_intattr;
834
835
0
    size_floatattr.resize(ifs.GetNumFloatAttributes());
836
0
    size_intattr.resize(ifs.GetNumIntAttributes());
837
838
0
    decoded_data_size = size_coordindex + size_coord + size_normal;
839
0
    for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
840
        // size = number_of_elements * components_per_element * size_of_component.
841
        // Note. But as you can see above, at first we are use this variable in meaning "count". After checking count of objects...
842
0
        size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
843
844
0
        switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
845
0
        case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
846
            // Check situation when encoded data contain texture coordinates but primitive not.
847
0
            if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
848
0
                if (primitives[0].attributes.texcoord[idx]->count != tval)
849
0
                    throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval),
850
0
                            ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ").");
851
852
0
                idx_texcoord++;
853
0
            } else {
854
0
                ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute.
855
0
            }
856
857
0
            break;
858
0
        default:
859
0
            throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
860
0
        }
861
862
0
        tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array.
863
0
        size_floatattr[idx] = tval;
864
0
        decoded_data_size += tval;
865
0
    }
866
867
0
    for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
868
        // size = number_of_elements * components_per_element * size_of_component. See float attributes note.
869
0
        size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
870
0
        switch (ifs.GetIntAttributeType(static_cast<unsigned long>(idx))) {
871
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
872
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
873
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
874
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
875
0
            break;
876
877
0
        default:
878
0
            throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
879
0
        }
880
881
0
        tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note.
882
0
        size_intattr[idx] = tval;
883
0
        decoded_data_size += tval;
884
0
    }
885
886
    // Create array for decoded data.
887
0
    decoded_data = new uint8_t[decoded_data_size];
888
889
    /****************** Set right array regions for decoder ******************/
890
891
0
    auto get_buf_offset = [](Ref<Accessor> &pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
892
893
    // Indices
894
0
    ifs.SetCoordIndex((IndicesType *)(decoded_data + get_buf_offset(primitives[0].indices)));
895
    // Coordinates
896
0
    ifs.SetCoord((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
897
    // Normals
898
0
    if (size_normal) {
899
0
        ifs.SetNormal((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
900
0
    }
901
902
0
    for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
903
0
        switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
904
0
        case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
905
0
            if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
906
                // See above about absent attributes.
907
0
                ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
908
0
                idx_texcoord++;
909
0
            }
910
911
0
            break;
912
0
        default:
913
0
            throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
914
0
        }
915
0
    }
916
917
0
    for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
918
0
        switch (ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
919
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
920
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
921
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
922
0
        case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
923
0
            break;
924
925
        // ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
926
0
        default:
927
0
            throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
928
0
        }
929
0
    }
930
931
    //
932
    // Decode data
933
    //
934
0
    if (decoder.DecodePayload(ifs, bstream) != o3dgc::O3DGC_OK) {
935
0
        throw DeadlyImportError("GLTF: can not decode Open3DGC data.");
936
0
    }
937
938
    // Set encoded region for "buffer".
939
0
    buf->EncodedRegion_Mark(pCompression_Open3DGC.Offset, pCompression_Open3DGC.Count, decoded_data, decoded_data_size, id);
940
    // No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data".
941
    // "delete [] output_data;"
942
0
}
943
#endif
944
945
0
inline void Camera::Read(Value &obj, Asset & /*r*/) {
946
0
    type = MemberOrDefault(obj, "type", Camera::Perspective);
947
948
0
    const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
949
950
0
    Value *it = FindObject(obj, subobjId);
951
0
    if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
952
953
0
    if (type == Camera::Perspective) {
954
0
        perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
955
0
        perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f / 2.f);
956
0
        perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
957
0
        perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
958
0
    } else {
959
0
        ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
960
0
        ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
961
0
        ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
962
0
        ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
963
0
    }
964
0
}
965
966
0
inline void Light::Read(Value &obj, Asset & /*r*/) {
967
0
    SetDefaults();
968
969
0
    Value *curType = FindString(obj, "type");
970
0
    if (nullptr != curType) {
971
0
        const char *t = curType->GetString();
972
0
        if (strcmp(t, "ambient") == 0)
973
0
            this->type = Type_ambient;
974
0
        else if (strcmp(t, "directional") == 0)
975
0
            this->type = Type_directional;
976
0
        else if (strcmp(t, "point") == 0)
977
0
            this->type = Type_point;
978
0
        else if (strcmp(t, "spot") == 0)
979
0
            this->type = Type_spot;
980
981
0
        if (this->type != Type_undefined) {
982
0
            if (Value *vals = FindString(obj, t)) {
983
0
                ReadMember(*vals, "color", color);
984
985
0
                ReadMember(*vals, "constantAttenuation", constantAttenuation);
986
0
                ReadMember(*vals, "linearAttenuation", linearAttenuation);
987
0
                ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation);
988
0
                ReadMember(*vals, "distance", distance);
989
990
0
                ReadMember(*vals, "falloffAngle", falloffAngle);
991
0
                ReadMember(*vals, "falloffExponent", falloffExponent);
992
0
            }
993
0
        }
994
0
    }
995
0
}
996
997
0
inline void Light::SetDefaults() {
998
#ifndef M_PI
999
    const float M_PI = 3.14159265358979323846f;
1000
#endif
1001
1002
0
    type = Type_undefined;
1003
1004
0
    SetVector(color, 0.f, 0.f, 0.f, 1.f);
1005
1006
0
    constantAttenuation = 0.f;
1007
0
    linearAttenuation = 1.f;
1008
0
    quadraticAttenuation = 1.f;
1009
0
    distance = 0.f;
1010
1011
0
    falloffAngle = static_cast<float>(M_PI / 2.f);
1012
0
    falloffExponent = 0.f;
1013
0
}
1014
1015
0
inline void Node::Read(Value &obj, Asset &r) {
1016
0
    if (name.empty()) {
1017
0
        name = id;
1018
0
    }
1019
1020
0
    Value *curChildren = FindArray(obj, "children");
1021
0
    if (nullptr != curChildren) {
1022
0
        this->children.reserve(curChildren->Size());
1023
0
        for (unsigned int i = 0; i < curChildren->Size(); ++i) {
1024
0
            Value &child = (*curChildren)[i];
1025
0
            if (child.IsString()) {
1026
                // get/create the child node
1027
0
                Ref<Node> chn = r.nodes.Get(child.GetString());
1028
0
                if (chn) this->children.push_back(chn);
1029
0
            }
1030
0
        }
1031
0
    }
1032
1033
0
    Value *curMatrix = FindArray(obj, "matrix");
1034
0
    if (nullptr != curMatrix) {
1035
0
        ReadValue(*curMatrix, this->matrix);
1036
0
    } else {
1037
0
        ReadMember(obj, "translation", translation);
1038
0
        ReadMember(obj, "scale", scale);
1039
0
        ReadMember(obj, "rotation", rotation);
1040
0
    }
1041
1042
0
    Value *curMeshes = FindArray(obj, "meshes");
1043
0
    if (nullptr != curMeshes) {
1044
0
        unsigned int numMeshes = (unsigned int)curMeshes->Size();
1045
1046
0
        std::vector<unsigned int> meshList;
1047
1048
0
        this->meshes.reserve(numMeshes);
1049
0
        for (unsigned i = 0; i < numMeshes; ++i) {
1050
0
            if ((*curMeshes)[i].IsString()) {
1051
0
                Ref<Mesh> mesh = r.meshes.Get((*curMeshes)[i].GetString());
1052
0
                if (mesh) {
1053
0
                    this->meshes.push_back(mesh);
1054
0
                }
1055
0
            }
1056
0
        }
1057
0
    }
1058
1059
0
    Value *curCamera = FindString(obj, "camera");
1060
0
    if (nullptr != curCamera) {
1061
0
        this->camera = r.cameras.Get(curCamera->GetString());
1062
0
        if (this->camera) {
1063
0
            this->camera->id = this->id;
1064
0
        }
1065
0
    }
1066
1067
    // TODO load "skeletons", "skin", "jointName"
1068
1069
0
    if (Value *extensions = FindObject(obj, "extensions")) {
1070
0
        if (r.extensionsUsed.KHR_materials_common) {
1071
1072
0
            if (Value *ext = FindObject(*extensions, "KHR_materials_common")) {
1073
0
                Value *curLight = FindString(*ext, "light");
1074
0
                if (nullptr != curLight) {
1075
0
                    this->light = r.lights.Get(curLight->GetString());
1076
0
                }
1077
0
            }
1078
0
        }
1079
0
    }
1080
0
}
1081
1082
0
inline void Scene::Read(Value &obj, Asset &r) {
1083
0
    if (Value *array = FindArray(obj, "nodes")) {
1084
0
        for (unsigned int i = 0; i < array->Size(); ++i) {
1085
0
            if (!(*array)[i].IsString()) continue;
1086
0
            Ref<Node> node = r.nodes.Get((*array)[i].GetString());
1087
0
            if (node)
1088
0
                this->nodes.push_back(node);
1089
0
        }
1090
0
    }
1091
0
}
1092
1093
0
inline void AssetMetadata::Read(Document &doc) {
1094
    // read the version, etc.
1095
0
    if (Value *obj = FindObject(doc, "asset")) {
1096
0
        ReadMember(*obj, "copyright", copyright);
1097
0
        ReadMember(*obj, "generator", generator);
1098
1099
0
        premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
1100
1101
0
        if (Value *versionString = FindString(*obj, "version")) {
1102
0
            version = versionString->GetString();
1103
0
        } else if (Value *versionNumber = FindNumber(*obj, "version")) {
1104
0
            char buf[4];
1105
1106
0
            ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
1107
1108
0
            version = buf;
1109
0
        }
1110
1111
0
        Value *curProfile = FindObject(*obj, "profile");
1112
0
        if (nullptr != curProfile) {
1113
0
            ReadMember(*curProfile, "api", this->profile.api);
1114
0
            ReadMember(*curProfile, "version", this->profile.version);
1115
0
        }
1116
0
    }
1117
0
}
1118
1119
//
1120
// Asset methods implementation
1121
//
1122
1123
0
inline void Asset::ReadBinaryHeader(IOStream &stream) {
1124
0
    GLB_Header header;
1125
0
    if (stream.Read(&header, sizeof(header), 1) != 1) {
1126
0
        throw DeadlyImportError("GLTF: Unable to read the file header");
1127
0
    }
1128
1129
0
    if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
1130
0
        throw DeadlyImportError("GLTF: Invalid binary glTF file");
1131
0
    }
1132
1133
0
    AI_SWAP4(header.version);
1134
0
    asset.version = ai_to_string(header.version);
1135
0
    if (header.version != 1) {
1136
0
        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
1137
0
    }
1138
1139
0
    AI_SWAP4(header.sceneFormat);
1140
0
    if (header.sceneFormat != SceneFormat_JSON) {
1141
0
        throw DeadlyImportError("GLTF: Unsupported binary glTF scene format");
1142
0
    }
1143
1144
0
    AI_SWAP4(header.length);
1145
0
    AI_SWAP4(header.sceneLength);
1146
1147
0
    static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
1148
0
    mSceneLength = static_cast<size_t>(header.sceneLength); // Can't be larger than 4GB (max. uint32_t)
1149
1150
0
    mBodyOffset = sizeof(header) + mSceneLength;
1151
0
    mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
1152
1153
0
    mBodyLength = header.length - mBodyOffset;
1154
0
}
1155
1156
39
inline void Asset::Load(const std::string &pFile, bool isBinary) {
1157
39
    mCurrentAssetDir.clear();
1158
1159
    /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
1160
    if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);*/
1161
39
    if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
1162
0
        mCurrentAssetDir = getCurrentAssetDir(pFile);
1163
0
    }
1164
1165
39
    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
1166
39
    if (!stream) {
1167
0
        throw DeadlyImportError("GLTF: Could not open file for reading");
1168
0
    }
1169
1170
    // is binary? then read the header
1171
39
    if (isBinary) {
1172
0
        SetAsBinary(); // also creates the body buffer
1173
0
        ReadBinaryHeader(*stream);
1174
39
    } else {
1175
39
        mSceneLength = stream->FileSize();
1176
39
        mBodyLength = 0;
1177
39
    }
1178
1179
    // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
1180
39
    if (mSceneLength < 2) {
1181
0
        throw DeadlyImportError("GLTF: No JSON file contents");
1182
0
    }
1183
1184
    // Binary format only supports up to 4GB of JSON so limit it there to avoid extreme memory allocation
1185
39
    if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
1186
0
        throw DeadlyImportError("GLTF: JSON size greater than 4GB");
1187
0
    }
1188
1189
    // read the scene data, ensure null termination
1190
39
    std::vector<char> sceneData(mSceneLength + 1);
1191
39
    sceneData[mSceneLength] = '\0';
1192
1193
39
    if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
1194
0
        throw DeadlyImportError("GLTF: Could not read the file contents");
1195
0
    }
1196
1197
    // parse the JSON document
1198
1199
39
    Document doc;
1200
39
    doc.ParseInsitu(&sceneData[0]);
1201
1202
39
    if (doc.HasParseError()) {
1203
38
        char buffer[32];
1204
38
        ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
1205
38
        throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
1206
38
    }
1207
1208
1
    if (!doc.IsObject()) {
1209
1
        throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
1210
1
    }
1211
1212
    // Fill the buffer instance for the current file embedded contents
1213
0
    if (mBodyLength > 0) {
1214
0
        if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
1215
0
            throw DeadlyImportError("GLTF: Unable to read gltf file");
1216
0
        }
1217
0
    }
1218
1219
    // Load the metadata
1220
0
    asset.Read(doc);
1221
0
    if (!asset) {
1222
0
        return;
1223
0
    }
1224
1225
0
    ReadExtensionsUsed(doc);
1226
1227
    // Prepare the dictionaries
1228
0
    for (size_t i = 0; i < mDicts.size(); ++i) {
1229
0
        mDicts[i]->AttachToDocument(doc);
1230
0
    }
1231
1232
    // Read the "scene" property, which specifies which scene to load
1233
    // and recursively load everything referenced by it
1234
0
    Value *curScene = FindString(doc, "scene");
1235
0
    if (nullptr != curScene) {
1236
0
        this->scene = scenes.Get(curScene->GetString());
1237
0
    }
1238
1239
    // Clean up
1240
0
    for (size_t i = 0; i < mDicts.size(); ++i) {
1241
0
        mDicts[i]->DetachFromDocument();
1242
0
    }
1243
0
}
1244
1245
0
inline void Asset::SetAsBinary() {
1246
0
    if (!extensionsUsed.KHR_binary_glTF) {
1247
0
        extensionsUsed.KHR_binary_glTF = true;
1248
0
        mBodyBuffer = buffers.Create("binary_glTF");
1249
0
        mBodyBuffer->MarkAsSpecial();
1250
0
    }
1251
0
}
1252
1253
0
inline void Asset::ReadExtensionsUsed(Document &doc) {
1254
0
    Value *extsUsed = FindArray(doc, "extensionsUsed");
1255
0
    if (!extsUsed) return;
1256
1257
0
    std::gltf_unordered_map<std::string, bool> exts;
1258
1259
0
    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
1260
0
        if ((*extsUsed)[i].IsString()) {
1261
0
            exts[(*extsUsed)[i].GetString()] = true;
1262
0
        }
1263
0
    }
1264
1265
0
    CHECK_EXT(KHR_binary_glTF);
1266
0
    CHECK_EXT(KHR_materials_common);
1267
1268
0
#undef CHECK_EXT
1269
0
}
1270
1271
39
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool absolute) {
1272
39
#ifdef ASSIMP_API
1273
39
    (void)absolute;
1274
39
    return mIOSystem->Open(path, mode);
1275
#else
1276
    if (path.size() < 2) return 0;
1277
    if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
1278
        path = mCurrentAssetDir + path;
1279
    }
1280
    FILE *f = fopen(path.c_str(), mode);
1281
    return f ? new IOStream(f) : 0;
1282
#endif
1283
39
}
1284
1285
0
inline std::string Asset::FindUniqueID(const std::string &str, const char *suffix) {
1286
0
    std::string id = str;
1287
1288
0
    if (!id.empty()) {
1289
0
        if (mUsedIds.find(id) == mUsedIds.end())
1290
0
            return id;
1291
1292
0
        id += "_";
1293
0
    }
1294
1295
0
    id += suffix;
1296
1297
0
    Asset::IdMap::iterator it = mUsedIds.find(id);
1298
0
    if (it == mUsedIds.end())
1299
0
        return id;
1300
1301
0
    char buffer[1024];
1302
0
    int offset = ai_snprintf(buffer, sizeof(buffer), "%s_", id.c_str());
1303
0
    for (int i = 0; it != mUsedIds.end(); ++i) {
1304
0
        ai_snprintf(buffer + offset, sizeof(buffer) - offset, "%d", i);
1305
0
        id = buffer;
1306
0
        it = mUsedIds.find(id);
1307
0
    }
1308
1309
0
    return id;
1310
0
}
1311
1312
#if _MSC_VER
1313
#pragma warning(pop)
1314
#endif // _MSC_VER
1315
1316
} // namespace glTF