Coverage Report

Created: 2026-05-23 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/glTF2/glTF2Asset.inl
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, assimp team
6
7
All rights reserved.
8
9
Redistribution and use of this software in source and binary forms,
10
with or without modification, are permitted provided that the
11
following conditions are met:
12
13
* Redistributions of source code must retain the above
14
copyright notice, this list of conditions and the
15
following disclaimer.
16
17
* Redistributions in binary form must reproduce the above
18
copyright notice, this list of conditions and the
19
following disclaimer in the documentation and/or other
20
materials provided with the distribution.
21
22
* Neither the name of the assimp team, nor the names of its
23
contributors may be used to endorse or promote products
24
derived from this software without specific prior
25
written permission of the assimp team.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39
----------------------------------------------------------------------
40
*/
41
42
#include "AssetLib/glTFCommon/glTFCommon.h"
43
44
#include <assimp/MemoryIOWrapper.h>
45
#include <assimp/StringUtils.h>
46
#include <assimp/DefaultLogger.hpp>
47
#include <assimp/Base64.hpp>
48
#include <rapidjson/document.h>
49
#include <rapidjson/schema.h>
50
#include <rapidjson/stringbuffer.h>
51
52
// clang-format off
53
#ifdef ASSIMP_ENABLE_DRACO
54
55
// Google draco library headers spew many warnings. Bad Google, no cookie
56
#   if _MSC_VER
57
#       pragma warning(push)
58
#       pragma warning(disable : 4018) // Signed/unsigned mismatch
59
#       pragma warning(disable : 4804) // Unsafe use of type 'bool'
60
#   elif defined(__clang__)
61
#       pragma clang diagnostic push
62
#       pragma clang diagnostic ignored "-Wsign-compare"
63
#   elif defined(__GNUC__)
64
#       pragma GCC diagnostic push
65
#       if (__GNUC__ > 4)
66
#           pragma GCC diagnostic ignored "-Wbool-compare"
67
#       endif
68
#   pragma GCC diagnostic ignored "-Wsign-compare"
69
#endif
70
71
#include "draco/compression/decode.h"
72
#include "draco/core/decoder_buffer.h"
73
74
#if _MSC_VER
75
#   pragma warning(pop)
76
#elif defined(__clang__)
77
#   pragma clang diagnostic pop
78
#elif defined(__GNUC__)
79
#   pragma GCC diagnostic pop
80
#endif
81
#ifndef DRACO_MESH_COMPRESSION_SUPPORTED
82
#   error glTF: KHR_draco_mesh_compression: draco library must have DRACO_MESH_COMPRESSION_SUPPORTED
83
#endif
84
#endif
85
// clang-format on
86
87
using namespace Assimp;
88
89
namespace glTF2 {
90
91
using glTFCommon::FindStringInContext;
92
using glTFCommon::FindNumberInContext;
93
using glTFCommon::FindUIntInContext;
94
using glTFCommon::FindArrayInContext;
95
using glTFCommon::FindObjectInContext;
96
using glTFCommon::FindExtensionInContext;
97
using glTFCommon::MemberOrDefault;
98
using glTFCommon::ReadMember;
99
using glTFCommon::FindMember;
100
using glTFCommon::FindObject;
101
using glTFCommon::FindUInt;
102
using glTFCommon::FindArray;
103
using glTFCommon::FindArray;
104
105
namespace {
106
107
//
108
// JSON Value reading helpers
109
//
110
49.9k
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
111
49.9k
    CustomExtension ret;
112
49.9k
    ret.name = name;
113
49.9k
    if (obj.IsObject()) {
114
71
        ret.mValues.isPresent = true;
115
343
        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
116
272
            auto &val = it->value;
117
272
            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
118
272
        }
119
49.8k
    } else if (obj.IsArray()) {
120
108
        ret.mValues.value.reserve(obj.Size());
121
108
        ret.mValues.isPresent = true;
122
665
        for (unsigned int i = 0; i < obj.Size(); ++i) {
123
557
            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
124
557
        }
125
49.7k
    } else if (obj.IsNumber()) {
126
25.3k
        if (obj.IsUint64()) {
127
24.9k
            ret.mUint64Value.value = obj.GetUint64();
128
24.9k
            ret.mUint64Value.isPresent = true;
129
24.9k
        } else if (obj.IsInt64()) {
130
41
            ret.mInt64Value.value = obj.GetInt64();
131
41
            ret.mInt64Value.isPresent = true;
132
442
        } else if (obj.IsDouble()) {
133
442
            ret.mDoubleValue.value = obj.GetDouble();
134
442
            ret.mDoubleValue.isPresent = true;
135
442
        }
136
25.3k
    } else if (obj.IsString()) {
137
12.1k
        ReadValue(obj, ret.mStringValue);
138
12.1k
        ret.mStringValue.isPresent = true;
139
12.1k
    } else if (obj.IsBool()) {
140
12.1k
        ret.mBoolValue.value = obj.GetBool();
141
12.1k
        ret.mBoolValue.isPresent = true;
142
12.1k
    }
143
49.9k
    return ret;
144
49.9k
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::ReadExtensions(char const*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
glTF2Importer.cpp:glTF2::(anonymous namespace)::ReadExtensions(char const*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
Line
Count
Source
110
49.9k
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
111
49.9k
    CustomExtension ret;
112
49.9k
    ret.name = name;
113
49.9k
    if (obj.IsObject()) {
114
71
        ret.mValues.isPresent = true;
115
343
        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
116
272
            auto &val = it->value;
117
272
            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
118
272
        }
119
49.8k
    } else if (obj.IsArray()) {
120
108
        ret.mValues.value.reserve(obj.Size());
121
108
        ret.mValues.isPresent = true;
122
665
        for (unsigned int i = 0; i < obj.Size(); ++i) {
123
557
            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
124
557
        }
125
49.7k
    } else if (obj.IsNumber()) {
126
25.3k
        if (obj.IsUint64()) {
127
24.9k
            ret.mUint64Value.value = obj.GetUint64();
128
24.9k
            ret.mUint64Value.isPresent = true;
129
24.9k
        } else if (obj.IsInt64()) {
130
41
            ret.mInt64Value.value = obj.GetInt64();
131
41
            ret.mInt64Value.isPresent = true;
132
442
        } else if (obj.IsDouble()) {
133
442
            ret.mDoubleValue.value = obj.GetDouble();
134
442
            ret.mDoubleValue.isPresent = true;
135
442
        }
136
25.3k
    } else if (obj.IsString()) {
137
12.1k
        ReadValue(obj, ret.mStringValue);
138
12.1k
        ret.mStringValue.isPresent = true;
139
12.1k
    } else if (obj.IsBool()) {
140
12.1k
        ret.mBoolValue.value = obj.GetBool();
141
12.1k
        ret.mBoolValue.isPresent = true;
142
12.1k
    }
143
49.9k
    return ret;
144
49.9k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::ReadExtensions(char const*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
145
146
12.2k
inline Extras ReadExtras(Value &obj) {
147
12.2k
    Extras ret;
148
149
12.2k
    ret.mValues.reserve(obj.MemberCount());
150
61.3k
    for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
151
49.0k
        auto &val = it->value;
152
49.0k
        ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
153
49.0k
    }
154
155
12.2k
    return ret;
156
12.2k
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::ReadExtras(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
glTF2Importer.cpp:glTF2::(anonymous namespace)::ReadExtras(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
Line
Count
Source
146
12.2k
inline Extras ReadExtras(Value &obj) {
147
12.2k
    Extras ret;
148
149
12.2k
    ret.mValues.reserve(obj.MemberCount());
150
61.3k
    for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
151
49.0k
        auto &val = it->value;
152
49.0k
        ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
153
49.0k
    }
154
155
12.2k
    return ret;
156
12.2k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::ReadExtras(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
157
158
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
159
0
        uint8_t *dst, size_t dst_stride) {
160
0
    if (src_stride == dst_stride) {
161
0
        memcpy(dst, src, count * src_stride);
162
0
        return;
163
0
    }
164
165
0
    size_t sz = std::min(src_stride, dst_stride);
166
0
    for (size_t i = 0; i < count; ++i) {
167
0
        memcpy(dst, src, sz);
168
0
        if (sz < dst_stride) {
169
0
            memset(dst + sz, 0, dst_stride - sz);
170
0
        }
171
0
        src += src_stride;
172
0
        dst += dst_stride;
173
0
    }
174
0
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long)
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long)
175
176
23.2k
void SetVector(vec4 &v, const float (&in)[4]) {
177
23.2k
    v[0] = in[0];
178
23.2k
    v[1] = in[1];
179
23.2k
    v[2] = in[2];
180
23.2k
    v[3] = in[3];
181
23.2k
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [4], float const (&) [4])
glTF2Importer.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [4], float const (&) [4])
Line
Count
Source
176
23.2k
void SetVector(vec4 &v, const float (&in)[4]) {
177
23.2k
    v[0] = in[0];
178
23.2k
    v[1] = in[1];
179
23.2k
    v[2] = in[2];
180
23.2k
    v[3] = in[3];
181
23.2k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [4], float const (&) [4])
182
183
50.9k
void SetVector(vec3 &v, const float (&in)[3]) {
184
50.9k
    v[0] = in[0];
185
50.9k
    v[1] = in[1];
186
50.9k
    v[2] = in[2];
187
50.9k
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [3], float const (&) [3])
glTF2Importer.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [3], float const (&) [3])
Line
Count
Source
183
50.9k
void SetVector(vec3 &v, const float (&in)[3]) {
184
50.9k
    v[0] = in[0];
185
50.9k
    v[1] = in[1];
186
50.9k
    v[2] = in[2];
187
50.9k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [3], float const (&) [3])
188
189
template <int N>
190
57.4k
inline int Compare(const char *attr, const char (&str)[N]) {
191
57.4k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
57.4k
}
Unexecuted instantiation: ImporterRegistry.cpp:int glTF2::(anonymous namespace)::Compare<9>(char const*, char const (&) [9])
Unexecuted instantiation: ImporterRegistry.cpp:int glTF2::(anonymous namespace)::Compare<7>(char const*, char const (&) [7])
Unexecuted instantiation: ImporterRegistry.cpp:int glTF2::(anonymous namespace)::Compare<8>(char const*, char const (&) [8])
Unexecuted instantiation: ImporterRegistry.cpp:int glTF2::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Unexecuted instantiation: ImporterRegistry.cpp:int glTF2::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<9>(char const*, char const (&) [9])
Line
Count
Source
190
23.4k
inline int Compare(const char *attr, const char (&str)[N]) {
191
23.4k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
23.4k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<7>(char const*, char const (&) [7])
Line
Count
Source
190
16.0k
inline int Compare(const char *attr, const char (&str)[N]) {
191
16.0k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
16.0k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<8>(char const*, char const (&) [8])
Line
Count
Source
190
9.61k
inline int Compare(const char *attr, const char (&str)[N]) {
191
9.61k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
9.61k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Line
Count
Source
190
5.35k
inline int Compare(const char *attr, const char (&str)[N]) {
191
5.35k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
5.35k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
Line
Count
Source
190
2.92k
inline int Compare(const char *attr, const char (&str)[N]) {
191
2.92k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
2.92k
}
Unexecuted instantiation: glTF2Exporter.cpp:int glTF2::(anonymous namespace)::Compare<9>(char const*, char const (&) [9])
Unexecuted instantiation: glTF2Exporter.cpp:int glTF2::(anonymous namespace)::Compare<7>(char const*, char const (&) [7])
Unexecuted instantiation: glTF2Exporter.cpp:int glTF2::(anonymous namespace)::Compare<8>(char const*, char const (&) [8])
Unexecuted instantiation: glTF2Exporter.cpp:int glTF2::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Unexecuted instantiation: glTF2Exporter.cpp:int glTF2::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
193
194
#if _MSC_VER
195
#pragma warning(push)
196
#pragma warning(disable : 4706)
197
#endif // _MSC_VER
198
199
16.8k
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
200
16.8k
    if ((pos = Compare(attr, "POSITION"))) {
201
5.55k
        v = &(p.attributes.position);
202
11.2k
    } else if ((pos = Compare(attr, "NORMAL"))) {
203
4.62k
        v = &(p.attributes.normal);
204
6.65k
    } else if ((pos = Compare(attr, "TANGENT"))) {
205
64
        v = &(p.attributes.tangent);
206
6.59k
    } else if ((pos = Compare(attr, "TEXCOORD"))) {
207
1.23k
        v = &(p.attributes.texcoord);
208
5.35k
    } else if ((pos = Compare(attr, "COLOR"))) {
209
598
        v = &(p.attributes.color);
210
4.76k
    } else if ((pos = Compare(attr, "JOINTS"))) {
211
1.84k
        v = &(p.attributes.joint);
212
2.92k
    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
213
1
        v = &(p.attributes.jointmatrix);
214
2.91k
    } else if ((pos = Compare(attr, "WEIGHTS"))) {
215
1.78k
        v = &(p.attributes.weight);
216
1.78k
    } else
217
1.13k
        return false;
218
15.6k
    return true;
219
16.8k
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::GetAttribVector(glTF2::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
glTF2Importer.cpp:glTF2::(anonymous namespace)::GetAttribVector(glTF2::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
Line
Count
Source
199
16.8k
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
200
16.8k
    if ((pos = Compare(attr, "POSITION"))) {
201
5.55k
        v = &(p.attributes.position);
202
11.2k
    } else if ((pos = Compare(attr, "NORMAL"))) {
203
4.62k
        v = &(p.attributes.normal);
204
6.65k
    } else if ((pos = Compare(attr, "TANGENT"))) {
205
64
        v = &(p.attributes.tangent);
206
6.59k
    } else if ((pos = Compare(attr, "TEXCOORD"))) {
207
1.23k
        v = &(p.attributes.texcoord);
208
5.35k
    } else if ((pos = Compare(attr, "COLOR"))) {
209
598
        v = &(p.attributes.color);
210
4.76k
    } else if ((pos = Compare(attr, "JOINTS"))) {
211
1.84k
        v = &(p.attributes.joint);
212
2.92k
    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
213
1
        v = &(p.attributes.jointmatrix);
214
2.91k
    } else if ((pos = Compare(attr, "WEIGHTS"))) {
215
1.78k
        v = &(p.attributes.weight);
216
1.78k
    } else
217
1.13k
        return false;
218
15.6k
    return true;
219
16.8k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::GetAttribVector(glTF2::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
220
221
62
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
222
62
    if ((pos = Compare(attr, "POSITION"))) {
223
21
        v = &(p.targets[targetIndex].position);
224
41
    } else if ((pos = Compare(attr, "NORMAL"))) {
225
4
        v = &(p.targets[targetIndex].normal);
226
37
    } else if ((pos = Compare(attr, "TANGENT"))) {
227
10
        v = &(p.targets[targetIndex].tangent);
228
10
    } else
229
27
        return false;
230
35
    return true;
231
62
}
Unexecuted instantiation: ImporterRegistry.cpp:glTF2::(anonymous namespace)::GetAttribTargetVector(glTF2::Mesh::Primitive&, int, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
glTF2Importer.cpp:glTF2::(anonymous namespace)::GetAttribTargetVector(glTF2::Mesh::Primitive&, int, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
Line
Count
Source
221
62
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
222
62
    if ((pos = Compare(attr, "POSITION"))) {
223
21
        v = &(p.targets[targetIndex].position);
224
41
    } else if ((pos = Compare(attr, "NORMAL"))) {
225
4
        v = &(p.targets[targetIndex].normal);
226
37
    } else if ((pos = Compare(attr, "TANGENT"))) {
227
10
        v = &(p.targets[targetIndex].tangent);
228
10
    } else
229
27
        return false;
230
35
    return true;
231
62
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::GetAttribTargetVector(glTF2::Mesh::Primitive&, int, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >*&, int&)
232
233
} // namespace
234
235
7.69k
inline Value *Object::FindString(Value &val, const char *memberId) {
236
7.69k
    return FindStringInContext(val, memberId, id.c_str(), name.c_str());
237
7.69k
}
238
239
0
inline Value *Object::FindNumber(Value &val, const char *memberId) {
240
0
    return FindNumberInContext(val, memberId, id.c_str(), name.c_str());
241
0
}
242
243
152k
inline Value *Object::FindUInt(Value &val, const char *memberId) {
244
152k
    return FindUIntInContext(val, memberId, id.c_str(), name.c_str());
245
152k
}
246
247
84.1k
inline Value *Object::FindArray(Value &val, const char *memberId) {
248
84.1k
    return FindArrayInContext(val, memberId, id.c_str(), name.c_str());
249
84.1k
}
250
251
235k
inline Value *Object::FindObject(Value &val, const char *memberId) {
252
235k
    return FindObjectInContext(val, memberId, id.c_str(), name.c_str());
253
235k
}
254
255
3
inline Value *Object::FindExtension(Value &val, const char *extensionId) {
256
3
    return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
257
3
}
258
259
81.5k
inline void Object::ReadExtensions(Value &val) {
260
81.5k
    if (Value *curExtensions = FindObject(val, "extensions")) {
261
0
        this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
262
0
    }
263
81.5k
}
264
265
81.5k
inline void Object::ReadExtras(Value &val) {
266
81.5k
    if (Value *curExtras = FindObject(val, "extras")) {
267
12.2k
        this->extras = glTF2::ReadExtras(*curExtras);
268
12.2k
    }
269
81.5k
}
270
271
#ifdef ASSIMP_ENABLE_DRACO
272
273
template <typename T>
274
inline void CopyFaceIndex_Draco(Buffer &decodedIndexBuffer, const draco::Mesh &draco_mesh) {
275
    const size_t faceStride = sizeof(T) * 3;
276
    for (draco::FaceIndex f(0); f < draco_mesh.num_faces(); ++f) {
277
        const draco::Mesh::Face &face = draco_mesh.face(f);
278
        T indices[3] = { static_cast<T>(face[0].value()), static_cast<T>(face[1].value()), static_cast<T>(face[2].value()) };
279
        memcpy(decodedIndexBuffer.GetPointer() + (f.value() * faceStride), &indices[0], faceStride);
280
    }
281
}
282
283
inline void SetDecodedIndexBuffer_Draco(const draco::Mesh &dracoMesh, Mesh::Primitive &prim) {
284
    if (!prim.indices || dracoMesh.num_faces() == 0)
285
        return;
286
287
    // Create a decoded Index buffer (if there is one)
288
    size_t componentBytes = prim.indices->GetBytesPerComponent();
289
290
    std::unique_ptr<Buffer> decodedIndexBuffer(new Buffer());
291
    decodedIndexBuffer->Grow(dracoMesh.num_faces() * 3 * componentBytes);
292
293
    // If accessor uses the same size as draco implementation, copy the draco buffer directly
294
295
    // Usually uint32_t but shouldn't assume
296
    if (sizeof(dracoMesh.face(draco::FaceIndex(0))[0]) == componentBytes) {
297
        memcpy(decodedIndexBuffer->GetPointer(), &dracoMesh.face(draco::FaceIndex(0))[0], decodedIndexBuffer->byteLength);
298
        // Assign this alternate data buffer to the accessor
299
        prim.indices->decodedBuffer.swap(decodedIndexBuffer);
300
        return;
301
    }
302
303
    // Not same size, convert
304
    switch (componentBytes) {
305
    case sizeof(uint32_t):
306
        CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
307
        break;
308
    case sizeof(uint16_t):
309
        CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
310
        break;
311
    case sizeof(uint8_t):
312
        CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
313
        break;
314
    default:
315
        ai_assert(false);
316
        break;
317
    }
318
319
    // Assign this alternate data buffer to the accessor
320
    prim.indices->decodedBuffer.swap(decodedIndexBuffer);
321
}
322
323
template <typename T>
324
static bool GetAttributeForAllPoints_Draco(const draco::Mesh &dracoMesh,
325
        const draco::PointAttribute &dracoAttribute,
326
        Buffer &outBuffer) {
327
    size_t byteOffset = 0;
328
    T values[4] = { 0, 0, 0, 0 };
329
    for (draco::PointIndex i(0); i < dracoMesh.num_points(); ++i) {
330
        const draco::AttributeValueIndex val_index = dracoAttribute.mapped_index(i);
331
        if (!dracoAttribute.ConvertValue<T>(val_index, dracoAttribute.num_components(), values)) {
332
            return false;
333
        }
334
335
        memcpy(outBuffer.GetPointer() + byteOffset, &values[0], sizeof(T) * dracoAttribute.num_components());
336
        byteOffset += sizeof(T) * dracoAttribute.num_components();
337
    }
338
339
    return true;
340
}
341
342
inline void SetDecodedAttributeBuffer_Draco(const draco::Mesh &dracoMesh, uint32_t dracoAttribId, Accessor &accessor) {
343
    // Create decoded buffer
344
    const draco::PointAttribute *pDracoAttribute = dracoMesh.GetAttributeByUniqueId(dracoAttribId);
345
    if (pDracoAttribute == nullptr) {
346
        throw DeadlyImportError("GLTF: Invalid draco attribute id: ", dracoAttribId);
347
    }
348
349
    size_t componentBytes = accessor.GetBytesPerComponent();
350
351
    std::unique_ptr<Buffer> decodedAttribBuffer(new Buffer());
352
    decodedAttribBuffer->Grow(dracoMesh.num_points() * pDracoAttribute->num_components() * componentBytes);
353
354
    switch (accessor.componentType) {
355
    case ComponentType_BYTE:
356
        GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
357
        break;
358
    case ComponentType_UNSIGNED_BYTE:
359
        GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
360
        break;
361
    case ComponentType_SHORT:
362
        GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
363
        break;
364
    case ComponentType_UNSIGNED_SHORT:
365
        GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
366
        break;
367
    case ComponentType_UNSIGNED_INT:
368
        GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
369
        break;
370
    case ComponentType_FLOAT:
371
        GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
372
        break;
373
    default:
374
        ai_assert(false);
375
        break;
376
    }
377
378
    // Assign this alternate data buffer to the accessor
379
    accessor.decodedBuffer.swap(decodedAttribBuffer);
380
}
381
382
#endif // ASSIMP_ENABLE_DRACO
383
384
//
385
// LazyDict methods
386
//
387
388
template <class T>
389
inline LazyDict<T>::LazyDict(Asset &asset, const char *dictId, const char *extId) :
390
285k
        mDictId(dictId),
391
285k
        mExtId(extId),
392
285k
        mDict(nullptr),
393
285k
        mAsset(asset) {
394
285k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
285k
}
glTF2::LazyDict<glTF2::Accessor>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Animation>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Buffer>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::BufferView>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Camera>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Light>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Image>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Material>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Mesh>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Node>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Sampler>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Scene>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Skin>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
glTF2::LazyDict<glTF2::Texture>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
20.3k
        mDictId(dictId),
391
20.3k
        mExtId(extId),
392
20.3k
        mDict(nullptr),
393
20.3k
        mAsset(asset) {
394
20.3k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
20.3k
}
396
397
template <class T>
398
285k
inline LazyDict<T>::~LazyDict() {
399
375k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
89.8k
        delete mObjs[i];
401
89.8k
    }
402
285k
}
glTF2::LazyDict<glTF2::Texture>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
20.6k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
235
        delete mObjs[i];
401
235
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Skin>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
25.0k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
4.69k
        delete mObjs[i];
401
4.69k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Scene>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
24.6k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
4.29k
        delete mObjs[i];
401
4.29k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Sampler>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
20.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
181
        delete mObjs[i];
401
181
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Node>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
45.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
25.1k
        delete mObjs[i];
401
25.1k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Mesh>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
26.2k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
5.82k
        delete mObjs[i];
401
5.82k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Material>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
25.0k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
4.63k
        delete mObjs[i];
401
4.63k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Image>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
20.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
205
        delete mObjs[i];
401
205
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Light>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
20.3k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
0
        delete mObjs[i];
401
0
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Camera>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
20.4k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
97
        delete mObjs[i];
401
97
    }
402
20.3k
}
glTF2::LazyDict<glTF2::BufferView>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
34.6k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
14.2k
        delete mObjs[i];
401
14.2k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Buffer>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
29.7k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
9.35k
        delete mObjs[i];
401
9.35k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Animation>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
21.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
1.19k
        delete mObjs[i];
401
1.19k
    }
402
20.3k
}
glTF2::LazyDict<glTF2::Accessor>::~LazyDict()
Line
Count
Source
398
20.3k
inline LazyDict<T>::~LazyDict() {
399
40.1k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
19.7k
        delete mObjs[i];
401
19.7k
    }
402
20.3k
}
403
404
template <class T>
405
84.5k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
84.5k
    Value *container = nullptr;
407
84.5k
    const char *context = nullptr;
408
409
84.5k
    if (mExtId) {
410
6.04k
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
78.5k
    } else {
415
78.5k
        container = &doc;
416
78.5k
        context = "the document";
417
78.5k
    }
418
419
84.5k
    if (container) {
420
78.5k
        mDict = FindArrayInContext(*container, mDictId, context);
421
78.5k
    }
422
84.5k
}
glTF2::LazyDict<glTF2::Accessor>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.06k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.06k
    Value *container = nullptr;
407
6.06k
    const char *context = nullptr;
408
409
6.06k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.06k
    } else {
415
6.06k
        container = &doc;
416
6.06k
        context = "the document";
417
6.06k
    }
418
419
6.06k
    if (container) {
420
6.06k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.06k
    }
422
6.06k
}
glTF2::LazyDict<glTF2::Animation>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.05k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.05k
    Value *container = nullptr;
407
6.05k
    const char *context = nullptr;
408
409
6.05k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.05k
    } else {
415
6.05k
        container = &doc;
416
6.05k
        context = "the document";
417
6.05k
    }
418
419
6.05k
    if (container) {
420
6.05k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.05k
    }
422
6.05k
}
glTF2::LazyDict<glTF2::Buffer>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.05k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.05k
    Value *container = nullptr;
407
6.05k
    const char *context = nullptr;
408
409
6.05k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.05k
    } else {
415
6.05k
        container = &doc;
416
6.05k
        context = "the document";
417
6.05k
    }
418
419
6.05k
    if (container) {
420
6.05k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.05k
    }
422
6.05k
}
glTF2::LazyDict<glTF2::BufferView>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.05k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.05k
    Value *container = nullptr;
407
6.05k
    const char *context = nullptr;
408
409
6.05k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.05k
    } else {
415
6.05k
        container = &doc;
416
6.05k
        context = "the document";
417
6.05k
    }
418
419
6.05k
    if (container) {
420
6.05k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.05k
    }
422
6.05k
}
glTF2::LazyDict<glTF2::Camera>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.04k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.04k
    Value *container = nullptr;
407
6.04k
    const char *context = nullptr;
408
409
6.04k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.04k
    } else {
415
6.04k
        container = &doc;
416
6.04k
        context = "the document";
417
6.04k
    }
418
419
6.04k
    if (container) {
420
6.04k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.04k
    }
422
6.04k
}
glTF2::LazyDict<glTF2::Light>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.04k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.04k
    Value *container = nullptr;
407
6.04k
    const char *context = nullptr;
408
409
6.04k
    if (mExtId) {
410
6.04k
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.04k
    } else {
415
0
        container = &doc;
416
0
        context = "the document";
417
0
    }
418
419
6.04k
    if (container) {
420
0
        mDict = FindArrayInContext(*container, mDictId, context);
421
0
    }
422
6.04k
}
glTF2::LazyDict<glTF2::Image>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.04k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.04k
    Value *container = nullptr;
407
6.04k
    const char *context = nullptr;
408
409
6.04k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.04k
    } else {
415
6.04k
        container = &doc;
416
6.04k
        context = "the document";
417
6.04k
    }
418
419
6.04k
    if (container) {
420
6.04k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.04k
    }
422
6.04k
}
glTF2::LazyDict<glTF2::Material>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.04k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.04k
    Value *container = nullptr;
407
6.04k
    const char *context = nullptr;
408
409
6.04k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.04k
    } else {
415
6.04k
        container = &doc;
416
6.04k
        context = "the document";
417
6.04k
    }
418
419
6.04k
    if (container) {
420
6.04k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.04k
    }
422
6.04k
}
glTF2::LazyDict<glTF2::Mesh>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.04k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.04k
    Value *container = nullptr;
407
6.04k
    const char *context = nullptr;
408
409
6.04k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.04k
    } else {
415
6.04k
        container = &doc;
416
6.04k
        context = "the document";
417
6.04k
    }
418
419
6.04k
    if (container) {
420
6.04k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.04k
    }
422
6.04k
}
glTF2::LazyDict<glTF2::Node>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.03k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.03k
    Value *container = nullptr;
407
6.03k
    const char *context = nullptr;
408
409
6.03k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.03k
    } else {
415
6.03k
        container = &doc;
416
6.03k
        context = "the document";
417
6.03k
    }
418
419
6.03k
    if (container) {
420
6.03k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.03k
    }
422
6.03k
}
glTF2::LazyDict<glTF2::Sampler>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.03k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.03k
    Value *container = nullptr;
407
6.03k
    const char *context = nullptr;
408
409
6.03k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.03k
    } else {
415
6.03k
        container = &doc;
416
6.03k
        context = "the document";
417
6.03k
    }
418
419
6.03k
    if (container) {
420
6.03k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.03k
    }
422
6.03k
}
glTF2::LazyDict<glTF2::Scene>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.02k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.02k
    Value *container = nullptr;
407
6.02k
    const char *context = nullptr;
408
409
6.02k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.02k
    } else {
415
6.02k
        container = &doc;
416
6.02k
        context = "the document";
417
6.02k
    }
418
419
6.02k
    if (container) {
420
6.02k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.02k
    }
422
6.02k
}
glTF2::LazyDict<glTF2::Skin>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.01k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.01k
    Value *container = nullptr;
407
6.01k
    const char *context = nullptr;
408
409
6.01k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.01k
    } else {
415
6.01k
        container = &doc;
416
6.01k
        context = "the document";
417
6.01k
    }
418
419
6.01k
    if (container) {
420
6.01k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.01k
    }
422
6.01k
}
glTF2::LazyDict<glTF2::Texture>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
6.01k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
6.01k
    Value *container = nullptr;
407
6.01k
    const char *context = nullptr;
408
409
6.01k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
6.01k
    } else {
415
6.01k
        container = &doc;
416
6.01k
        context = "the document";
417
6.01k
    }
418
419
6.01k
    if (container) {
420
6.01k
        mDict = FindArrayInContext(*container, mDictId, context);
421
6.01k
    }
422
6.01k
}
423
424
template <class T>
425
64.1k
inline void LazyDict<T>::DetachFromDocument() {
426
64.1k
    mDict = nullptr;
427
64.1k
}
glTF2::LazyDict<glTF2::Accessor>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Animation>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Buffer>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::BufferView>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Camera>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Light>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Image>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Material>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Mesh>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Node>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Sampler>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Scene>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Skin>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
glTF2::LazyDict<glTF2::Texture>::DetachFromDocument()
Line
Count
Source
425
4.58k
inline void LazyDict<T>::DetachFromDocument() {
426
4.58k
    mDict = nullptr;
427
4.58k
}
428
429
template <class T>
430
0
unsigned int LazyDict<T>::Remove(const char *id) {
431
0
    id = T::TranslateId(mAsset, id);
432
433
0
    typename IdDict::iterator objIt = mObjsById.find(id);
434
435
0
    if (objIt == mObjsById.end()) {
436
0
        throw DeadlyExportError("GLTF: Object with id \"" + std::string(id) + "\" is not found");
437
0
    }
438
439
0
    const unsigned int index = objIt->second;
440
441
0
    mObjsById.erase(id);
442
0
    mObjsByOIndex.erase(index);
443
0
    delete mObjs[index];
444
0
    mObjs.erase(mObjs.begin() + index);
445
446
    //update index of object in mObjs;
447
0
    for (unsigned int i = index; i < mObjs.size(); ++i) {
448
0
        T *obj = mObjs[i];
449
450
0
        obj->index = i;
451
0
    }
452
453
0
    for (IdDict::iterator it = mObjsById.begin(); it != mObjsById.end(); ++it) {
454
0
        if (it->second <= index) {
455
0
            continue;
456
0
        }
457
458
0
        mObjsById[it->first] = it->second - 1;
459
0
    }
460
461
0
    for (Dict::iterator it = mObjsByOIndex.begin(); it != mObjsByOIndex.end(); ++it) {
462
0
        if (it->second <= index) {
463
0
            continue;
464
0
        }
465
466
0
        mObjsByOIndex[it->first] = it->second - 1;
467
0
    }
468
469
0
    return index;
470
0
}
471
472
template <class T>
473
113k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
113k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
113k
    if (it != mObjsByOIndex.end()) { // already created?
476
25.7k
        return Ref<T>(mObjs, it->second);
477
25.7k
    }
478
479
    // read it from the JSON object
480
88.0k
    if (!mDict) {
481
117
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
117
    }
483
484
87.9k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
87.9k
    if (i >= mDict->Size()) {
489
393
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
393
    }
491
492
87.5k
    Value &obj = (*mDict)[i];
493
494
87.5k
    if (!obj.IsObject()) {
495
33
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
33
    }
497
498
87.5k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
39
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
39
    }
501
87.4k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
87.4k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
87.4k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
87.4k
    inst->oIndex = i;
508
87.4k
    ReadMember(obj, "name", inst->name);
509
87.4k
    inst->Read(obj, mAsset);
510
87.4k
    inst->ReadExtensions(obj);
511
87.4k
    inst->ReadExtras(obj);
512
513
87.4k
    Ref<T> result = Add(inst.release());
514
87.4k
    mRecursiveReferenceCheck.erase(i);
515
87.4k
    return result;
516
87.5k
}
glTF2::LazyDict<glTF2::Buffer>::Retrieve(unsigned int)
Line
Count
Source
473
14.7k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
14.7k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
14.7k
    if (it != mObjsByOIndex.end()) { // already created?
476
13.2k
        return Ref<T>(mObjs, it->second);
477
13.2k
    }
478
479
    // read it from the JSON object
480
1.54k
    if (!mDict) {
481
4
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
4
    }
483
484
1.53k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
1.53k
    if (i >= mDict->Size()) {
489
40
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
40
    }
491
492
1.49k
    Value &obj = (*mDict)[i];
493
494
1.49k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
1.49k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
1.49k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
1.49k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
1.49k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
1.49k
    inst->oIndex = i;
508
1.49k
    ReadMember(obj, "name", inst->name);
509
1.49k
    inst->Read(obj, mAsset);
510
1.49k
    inst->ReadExtensions(obj);
511
1.49k
    inst->ReadExtras(obj);
512
513
1.49k
    Ref<T> result = Add(inst.release());
514
1.49k
    mRecursiveReferenceCheck.erase(i);
515
1.49k
    return result;
516
1.49k
}
glTF2::LazyDict<glTF2::BufferView>::Retrieve(unsigned int)
Line
Count
Source
473
15.7k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
15.7k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
15.7k
    if (it != mObjsByOIndex.end()) { // already created?
476
898
        return Ref<T>(mObjs, it->second);
477
898
    }
478
479
    // read it from the JSON object
480
14.8k
    if (!mDict) {
481
18
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
18
    }
483
484
14.8k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
14.8k
    if (i >= mDict->Size()) {
489
36
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
36
    }
491
492
14.7k
    Value &obj = (*mDict)[i];
493
494
14.7k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
14.7k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
14.7k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
14.7k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
14.7k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
14.7k
    inst->oIndex = i;
508
14.7k
    ReadMember(obj, "name", inst->name);
509
14.7k
    inst->Read(obj, mAsset);
510
14.7k
    inst->ReadExtensions(obj);
511
14.7k
    inst->ReadExtras(obj);
512
513
14.7k
    Ref<T> result = Add(inst.release());
514
14.7k
    mRecursiveReferenceCheck.erase(i);
515
14.7k
    return result;
516
14.7k
}
glTF2::LazyDict<glTF2::Image>::Retrieve(unsigned int)
Line
Count
Source
473
229
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
229
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
229
    if (it != mObjsByOIndex.end()) { // already created?
476
0
        return Ref<T>(mObjs, it->second);
477
0
    }
478
479
    // read it from the JSON object
480
229
    if (!mDict) {
481
2
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
2
    }
483
484
227
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
227
    if (i >= mDict->Size()) {
489
6
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
6
    }
491
492
221
    Value &obj = (*mDict)[i];
493
494
221
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
220
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
220
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
220
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
220
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
220
    inst->oIndex = i;
508
220
    ReadMember(obj, "name", inst->name);
509
220
    inst->Read(obj, mAsset);
510
220
    inst->ReadExtensions(obj);
511
220
    inst->ReadExtras(obj);
512
513
220
    Ref<T> result = Add(inst.release());
514
220
    mRecursiveReferenceCheck.erase(i);
515
220
    return result;
516
220
}
glTF2::LazyDict<glTF2::Sampler>::Retrieve(unsigned int)
Line
Count
Source
473
189
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
189
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
189
    if (it != mObjsByOIndex.end()) { // already created?
476
0
        return Ref<T>(mObjs, it->second);
477
0
    }
478
479
    // read it from the JSON object
480
189
    if (!mDict) {
481
4
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
4
    }
483
484
185
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
185
    if (i >= mDict->Size()) {
489
3
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
3
    }
491
492
182
    Value &obj = (*mDict)[i];
493
494
182
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
181
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
181
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
181
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
181
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
181
    inst->oIndex = i;
508
181
    ReadMember(obj, "name", inst->name);
509
181
    inst->Read(obj, mAsset);
510
181
    inst->ReadExtensions(obj);
511
181
    inst->ReadExtras(obj);
512
513
181
    Ref<T> result = Add(inst.release());
514
181
    mRecursiveReferenceCheck.erase(i);
515
181
    return result;
516
181
}
glTF2::LazyDict<glTF2::Texture>::Retrieve(unsigned int)
Line
Count
Source
473
348
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
348
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
348
    if (it != mObjsByOIndex.end()) { // already created?
476
67
        return Ref<T>(mObjs, it->second);
477
67
    }
478
479
    // read it from the JSON object
480
281
    if (!mDict) {
481
4
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
4
    }
483
484
277
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
277
    if (i >= mDict->Size()) {
489
5
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
5
    }
491
492
272
    Value &obj = (*mDict)[i];
493
494
272
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
271
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
271
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
271
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
271
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
271
    inst->oIndex = i;
508
271
    ReadMember(obj, "name", inst->name);
509
271
    inst->Read(obj, mAsset);
510
271
    inst->ReadExtensions(obj);
511
271
    inst->ReadExtras(obj);
512
513
271
    Ref<T> result = Add(inst.release());
514
271
    mRecursiveReferenceCheck.erase(i);
515
271
    return result;
516
271
}
glTF2::LazyDict<glTF2::Accessor>::Retrieve(unsigned int)
Line
Count
Source
473
21.8k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
21.8k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
21.8k
    if (it != mObjsByOIndex.end()) { // already created?
476
1.14k
        return Ref<T>(mObjs, it->second);
477
1.14k
    }
478
479
    // read it from the JSON object
480
20.6k
    if (!mDict) {
481
33
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
33
    }
483
484
20.6k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
20.6k
    if (i >= mDict->Size()) {
489
96
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
96
    }
491
492
20.5k
    Value &obj = (*mDict)[i];
493
494
20.5k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
20.5k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
20.5k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
20.5k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
20.5k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
20.5k
    inst->oIndex = i;
508
20.5k
    ReadMember(obj, "name", inst->name);
509
20.5k
    inst->Read(obj, mAsset);
510
20.5k
    inst->ReadExtensions(obj);
511
20.5k
    inst->ReadExtras(obj);
512
513
20.5k
    Ref<T> result = Add(inst.release());
514
20.5k
    mRecursiveReferenceCheck.erase(i);
515
20.5k
    return result;
516
20.5k
}
glTF2::LazyDict<glTF2::Material>::Retrieve(unsigned int)
Line
Count
Source
473
4.77k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
4.77k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
4.77k
    if (it != mObjsByOIndex.end()) { // already created?
476
76
        return Ref<T>(mObjs, it->second);
477
76
    }
478
479
    // read it from the JSON object
480
4.69k
    if (!mDict) {
481
3
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
3
    }
483
484
4.69k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
4.69k
    if (i >= mDict->Size()) {
489
12
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
12
    }
491
492
4.68k
    Value &obj = (*mDict)[i];
493
494
4.68k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
4.67k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
4.67k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
4.67k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
4.67k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
4.67k
    inst->oIndex = i;
508
4.67k
    ReadMember(obj, "name", inst->name);
509
4.67k
    inst->Read(obj, mAsset);
510
4.67k
    inst->ReadExtensions(obj);
511
4.67k
    inst->ReadExtras(obj);
512
513
4.67k
    Ref<T> result = Add(inst.release());
514
4.67k
    mRecursiveReferenceCheck.erase(i);
515
4.67k
    return result;
516
4.67k
}
glTF2::LazyDict<glTF2::Node>::Retrieve(unsigned int)
Line
Count
Source
473
35.6k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
35.6k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
35.6k
    if (it != mObjsByOIndex.end()) { // already created?
476
8.51k
        return Ref<T>(mObjs, it->second);
477
8.51k
    }
478
479
    // read it from the JSON object
480
27.0k
    if (!mDict) {
481
19
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
19
    }
483
484
27.0k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
27.0k
    if (i >= mDict->Size()) {
489
138
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
138
    }
491
492
26.9k
    Value &obj = (*mDict)[i];
493
494
26.9k
    if (!obj.IsObject()) {
495
4
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
4
    }
497
498
26.9k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
39
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
39
    }
501
26.8k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
26.8k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
26.8k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
26.8k
    inst->oIndex = i;
508
26.8k
    ReadMember(obj, "name", inst->name);
509
26.8k
    inst->Read(obj, mAsset);
510
26.8k
    inst->ReadExtensions(obj);
511
26.8k
    inst->ReadExtras(obj);
512
513
26.8k
    Ref<T> result = Add(inst.release());
514
26.8k
    mRecursiveReferenceCheck.erase(i);
515
26.8k
    return result;
516
26.9k
}
glTF2::LazyDict<glTF2::Mesh>::Retrieve(unsigned int)
Line
Count
Source
473
8.62k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
8.62k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
8.62k
    if (it != mObjsByOIndex.end()) { // already created?
476
1.81k
        return Ref<T>(mObjs, it->second);
477
1.81k
    }
478
479
    // read it from the JSON object
480
6.81k
    if (!mDict) {
481
29
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
29
    }
483
484
6.78k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
6.78k
    if (i >= mDict->Size()) {
489
43
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
43
    }
491
492
6.74k
    Value &obj = (*mDict)[i];
493
494
6.74k
    if (!obj.IsObject()) {
495
5
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
5
    }
497
498
6.73k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
6.73k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
6.73k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
6.73k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
6.73k
    inst->oIndex = i;
508
6.73k
    ReadMember(obj, "name", inst->name);
509
6.73k
    inst->Read(obj, mAsset);
510
6.73k
    inst->ReadExtensions(obj);
511
6.73k
    inst->ReadExtras(obj);
512
513
6.73k
    Ref<T> result = Add(inst.release());
514
6.73k
    mRecursiveReferenceCheck.erase(i);
515
6.73k
    return result;
516
6.73k
}
glTF2::LazyDict<glTF2::Camera>::Retrieve(unsigned int)
Line
Count
Source
473
133
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
133
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
133
    if (it != mObjsByOIndex.end()) { // already created?
476
6
        return Ref<T>(mObjs, it->second);
477
6
    }
478
479
    // read it from the JSON object
480
127
    if (!mDict) {
481
1
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
1
    }
483
484
126
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
126
    if (i >= mDict->Size()) {
489
14
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
14
    }
491
492
112
    Value &obj = (*mDict)[i];
493
494
112
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
111
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
111
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
111
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
111
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
111
    inst->oIndex = i;
508
111
    ReadMember(obj, "name", inst->name);
509
111
    inst->Read(obj, mAsset);
510
111
    inst->ReadExtensions(obj);
511
111
    inst->ReadExtras(obj);
512
513
111
    Ref<T> result = Add(inst.release());
514
111
    mRecursiveReferenceCheck.erase(i);
515
111
    return result;
516
111
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Light>::Retrieve(unsigned int)
glTF2::LazyDict<glTF2::Scene>::Retrieve(unsigned int)
Line
Count
Source
473
5.51k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
5.51k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
5.51k
    if (it != mObjsByOIndex.end()) { // already created?
476
0
        return Ref<T>(mObjs, it->second);
477
0
    }
478
479
    // read it from the JSON object
480
5.51k
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
5.51k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
5.51k
    if (i >= mDict->Size()) {
489
0
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
0
    }
491
492
5.51k
    Value &obj = (*mDict)[i];
493
494
5.51k
    if (!obj.IsObject()) {
495
13
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
13
    }
497
498
5.50k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
5.50k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
5.50k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
5.50k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
5.50k
    inst->oIndex = i;
508
5.50k
    ReadMember(obj, "name", inst->name);
509
5.50k
    inst->Read(obj, mAsset);
510
5.50k
    inst->ReadExtensions(obj);
511
5.50k
    inst->ReadExtras(obj);
512
513
5.50k
    Ref<T> result = Add(inst.release());
514
5.50k
    mRecursiveReferenceCheck.erase(i);
515
5.50k
    return result;
516
5.50k
}
glTF2::LazyDict<glTF2::Skin>::Retrieve(unsigned int)
Line
Count
Source
473
4.80k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
4.80k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
4.80k
    if (it != mObjsByOIndex.end()) { // already created?
476
0
        return Ref<T>(mObjs, it->second);
477
0
    }
478
479
    // read it from the JSON object
480
4.80k
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
4.80k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
4.80k
    if (i >= mDict->Size()) {
489
0
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
0
    }
491
492
4.80k
    Value &obj = (*mDict)[i];
493
494
4.80k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
4.80k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
4.80k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
4.80k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
4.80k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
4.80k
    inst->oIndex = i;
508
4.80k
    ReadMember(obj, "name", inst->name);
509
4.80k
    inst->Read(obj, mAsset);
510
4.80k
    inst->ReadExtensions(obj);
511
4.80k
    inst->ReadExtras(obj);
512
513
4.80k
    Ref<T> result = Add(inst.release());
514
4.80k
    mRecursiveReferenceCheck.erase(i);
515
4.80k
    return result;
516
4.80k
}
glTF2::LazyDict<glTF2::Animation>::Retrieve(unsigned int)
Line
Count
Source
473
1.27k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
1.27k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
1.27k
    if (it != mObjsByOIndex.end()) { // already created?
476
0
        return Ref<T>(mObjs, it->second);
477
0
    }
478
479
    // read it from the JSON object
480
1.27k
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
1.27k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
1.27k
    if (i >= mDict->Size()) {
489
0
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
0
    }
491
492
1.27k
    Value &obj = (*mDict)[i];
493
494
1.27k
    if (!obj.IsObject()) {
495
2
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
2
    }
497
498
1.26k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
0
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
0
    }
501
1.26k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
1.26k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
1.26k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
1.26k
    inst->oIndex = i;
508
1.26k
    ReadMember(obj, "name", inst->name);
509
1.26k
    inst->Read(obj, mAsset);
510
1.26k
    inst->ReadExtensions(obj);
511
1.26k
    inst->ReadExtras(obj);
512
513
1.26k
    Ref<T> result = Add(inst.release());
514
1.26k
    mRecursiveReferenceCheck.erase(i);
515
1.26k
    return result;
516
1.26k
}
517
518
template <class T>
519
985
Ref<T> LazyDict<T>::Get(unsigned int i) {
520
985
    return Ref<T>(mObjs, i);
521
985
}
glTF2::LazyDict<glTF2::Skin>::Get(unsigned int)
Line
Count
Source
519
985
Ref<T> LazyDict<T>::Get(unsigned int i) {
520
985
    return Ref<T>(mObjs, i);
521
985
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Buffer>::Get(unsigned int)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Texture>::Get(unsigned int)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Material>::Get(unsigned int)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Node>::Get(unsigned int)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Mesh>::Get(unsigned int)
522
523
template <class T>
524
0
Ref<T> LazyDict<T>::Get(const char *id) {
525
0
    id = T::TranslateId(mAsset, id);
526
527
0
    typename IdDict::iterator it = mObjsById.find(id);
528
0
    if (it != mObjsById.end()) { // already created?
529
0
        return Ref<T>(mObjs, it->second);
530
0
    }
531
532
0
    return Ref<T>();
533
0
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Sampler>::Get(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Node>::Get(char const*)
534
535
template <class T>
536
89.8k
Ref<T> LazyDict<T>::Add(T *obj) {
537
89.8k
    unsigned int idx = unsigned(mObjs.size());
538
89.8k
    mObjs.push_back(obj);
539
89.8k
    mObjsByOIndex[obj->oIndex] = idx;
540
89.8k
    mObjsById[obj->id] = idx;
541
89.8k
    return Ref<T>(mObjs, idx);
542
89.8k
}
glTF2::LazyDict<glTF2::Buffer>::Add(glTF2::Buffer*)
Line
Count
Source
536
9.35k
Ref<T> LazyDict<T>::Add(T *obj) {
537
9.35k
    unsigned int idx = unsigned(mObjs.size());
538
9.35k
    mObjs.push_back(obj);
539
9.35k
    mObjsByOIndex[obj->oIndex] = idx;
540
9.35k
    mObjsById[obj->id] = idx;
541
9.35k
    return Ref<T>(mObjs, idx);
542
9.35k
}
glTF2::LazyDict<glTF2::BufferView>::Add(glTF2::BufferView*)
Line
Count
Source
536
14.2k
Ref<T> LazyDict<T>::Add(T *obj) {
537
14.2k
    unsigned int idx = unsigned(mObjs.size());
538
14.2k
    mObjs.push_back(obj);
539
14.2k
    mObjsByOIndex[obj->oIndex] = idx;
540
14.2k
    mObjsById[obj->id] = idx;
541
14.2k
    return Ref<T>(mObjs, idx);
542
14.2k
}
glTF2::LazyDict<glTF2::Image>::Add(glTF2::Image*)
Line
Count
Source
536
205
Ref<T> LazyDict<T>::Add(T *obj) {
537
205
    unsigned int idx = unsigned(mObjs.size());
538
205
    mObjs.push_back(obj);
539
205
    mObjsByOIndex[obj->oIndex] = idx;
540
205
    mObjsById[obj->id] = idx;
541
205
    return Ref<T>(mObjs, idx);
542
205
}
glTF2::LazyDict<glTF2::Sampler>::Add(glTF2::Sampler*)
Line
Count
Source
536
181
Ref<T> LazyDict<T>::Add(T *obj) {
537
181
    unsigned int idx = unsigned(mObjs.size());
538
181
    mObjs.push_back(obj);
539
181
    mObjsByOIndex[obj->oIndex] = idx;
540
181
    mObjsById[obj->id] = idx;
541
181
    return Ref<T>(mObjs, idx);
542
181
}
glTF2::LazyDict<glTF2::Texture>::Add(glTF2::Texture*)
Line
Count
Source
536
235
Ref<T> LazyDict<T>::Add(T *obj) {
537
235
    unsigned int idx = unsigned(mObjs.size());
538
235
    mObjs.push_back(obj);
539
235
    mObjsByOIndex[obj->oIndex] = idx;
540
235
    mObjsById[obj->id] = idx;
541
235
    return Ref<T>(mObjs, idx);
542
235
}
glTF2::LazyDict<glTF2::Accessor>::Add(glTF2::Accessor*)
Line
Count
Source
536
19.7k
Ref<T> LazyDict<T>::Add(T *obj) {
537
19.7k
    unsigned int idx = unsigned(mObjs.size());
538
19.7k
    mObjs.push_back(obj);
539
19.7k
    mObjsByOIndex[obj->oIndex] = idx;
540
19.7k
    mObjsById[obj->id] = idx;
541
19.7k
    return Ref<T>(mObjs, idx);
542
19.7k
}
glTF2::LazyDict<glTF2::Material>::Add(glTF2::Material*)
Line
Count
Source
536
4.63k
Ref<T> LazyDict<T>::Add(T *obj) {
537
4.63k
    unsigned int idx = unsigned(mObjs.size());
538
4.63k
    mObjs.push_back(obj);
539
4.63k
    mObjsByOIndex[obj->oIndex] = idx;
540
4.63k
    mObjsById[obj->id] = idx;
541
4.63k
    return Ref<T>(mObjs, idx);
542
4.63k
}
glTF2::LazyDict<glTF2::Node>::Add(glTF2::Node*)
Line
Count
Source
536
25.1k
Ref<T> LazyDict<T>::Add(T *obj) {
537
25.1k
    unsigned int idx = unsigned(mObjs.size());
538
25.1k
    mObjs.push_back(obj);
539
25.1k
    mObjsByOIndex[obj->oIndex] = idx;
540
25.1k
    mObjsById[obj->id] = idx;
541
25.1k
    return Ref<T>(mObjs, idx);
542
25.1k
}
glTF2::LazyDict<glTF2::Mesh>::Add(glTF2::Mesh*)
Line
Count
Source
536
5.82k
Ref<T> LazyDict<T>::Add(T *obj) {
537
5.82k
    unsigned int idx = unsigned(mObjs.size());
538
5.82k
    mObjs.push_back(obj);
539
5.82k
    mObjsByOIndex[obj->oIndex] = idx;
540
5.82k
    mObjsById[obj->id] = idx;
541
5.82k
    return Ref<T>(mObjs, idx);
542
5.82k
}
glTF2::LazyDict<glTF2::Camera>::Add(glTF2::Camera*)
Line
Count
Source
536
97
Ref<T> LazyDict<T>::Add(T *obj) {
537
97
    unsigned int idx = unsigned(mObjs.size());
538
97
    mObjs.push_back(obj);
539
97
    mObjsByOIndex[obj->oIndex] = idx;
540
97
    mObjsById[obj->id] = idx;
541
97
    return Ref<T>(mObjs, idx);
542
97
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Light>::Add(glTF2::Light*)
glTF2::LazyDict<glTF2::Scene>::Add(glTF2::Scene*)
Line
Count
Source
536
4.29k
Ref<T> LazyDict<T>::Add(T *obj) {
537
4.29k
    unsigned int idx = unsigned(mObjs.size());
538
4.29k
    mObjs.push_back(obj);
539
4.29k
    mObjsByOIndex[obj->oIndex] = idx;
540
4.29k
    mObjsById[obj->id] = idx;
541
4.29k
    return Ref<T>(mObjs, idx);
542
4.29k
}
glTF2::LazyDict<glTF2::Skin>::Add(glTF2::Skin*)
Line
Count
Source
536
4.69k
Ref<T> LazyDict<T>::Add(T *obj) {
537
4.69k
    unsigned int idx = unsigned(mObjs.size());
538
4.69k
    mObjs.push_back(obj);
539
4.69k
    mObjsByOIndex[obj->oIndex] = idx;
540
4.69k
    mObjsById[obj->id] = idx;
541
4.69k
    return Ref<T>(mObjs, idx);
542
4.69k
}
glTF2::LazyDict<glTF2::Animation>::Add(glTF2::Animation*)
Line
Count
Source
536
1.19k
Ref<T> LazyDict<T>::Add(T *obj) {
537
1.19k
    unsigned int idx = unsigned(mObjs.size());
538
1.19k
    mObjs.push_back(obj);
539
1.19k
    mObjsByOIndex[obj->oIndex] = idx;
540
1.19k
    mObjsById[obj->id] = idx;
541
1.19k
    return Ref<T>(mObjs, idx);
542
1.19k
}
543
544
template <class T>
545
8.29k
Ref<T> LazyDict<T>::Create(const char *id) {
546
8.29k
    T *inst = new T();
547
8.29k
    unsigned int idx = unsigned(mObjs.size());
548
8.29k
    inst->id = id;
549
8.29k
    inst->index = idx;
550
8.29k
    inst->oIndex = idx;
551
8.29k
    return Add(inst);
552
8.29k
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::BufferView>::Create(char const*)
glTF2::LazyDict<glTF2::Buffer>::Create(char const*)
Line
Count
Source
545
8.29k
Ref<T> LazyDict<T>::Create(const char *id) {
546
8.29k
    T *inst = new T();
547
8.29k
    unsigned int idx = unsigned(mObjs.size());
548
8.29k
    inst->id = id;
549
8.29k
    inst->index = idx;
550
8.29k
    inst->oIndex = idx;
551
8.29k
    return Add(inst);
552
8.29k
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Accessor>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Sampler>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Texture>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Image>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Material>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Skin>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Mesh>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Node>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Scene>::Create(char const*)
Unexecuted instantiation: glTF2::LazyDict<glTF2::Animation>::Create(char const*)
553
554
//
555
// glTF dictionary objects methods
556
//
557
inline Buffer::Buffer() :
558
9.79k
        byteLength(0),
559
9.79k
        type(Type_arraybuffer),
560
9.79k
        EncodedRegion_Current(nullptr),
561
9.79k
        mIsSpecial(false) {
562
    // empty
563
9.79k
}
564
565
9.79k
inline Buffer::~Buffer() {
566
9.79k
    for (SEncodedRegion *reg : EncodedRegion_List) delete reg;
567
9.79k
}
568
569
0
inline const char *Buffer::TranslateId(Asset & /*r*/, const char *id) {
570
0
    return id;
571
0
}
572
573
1.49k
inline void Buffer::Read(Value &obj, Asset &r) {
574
1.49k
    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
575
1.49k
    byteLength = statedLength;
576
577
1.49k
    Value *it = FindString(obj, "uri");
578
1.49k
    if (!it) {
579
21
        if (statedLength > 0) {
580
11
            throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
581
11
        }
582
10
        return;
583
21
    }
584
585
1.47k
    const char *uri = it->GetString();
586
587
1.47k
    glTFCommon::Util::DataURI dataURI;
588
1.47k
    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
589
1.15k
        if (dataURI.base64) {
590
1.09k
            uint8_t *data = nullptr;
591
1.09k
            this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data);
592
1.09k
            this->mData.reset(data, std::default_delete<uint8_t[]>());
593
594
1.09k
            if (statedLength > 0 && this->byteLength != statedLength) {
595
19
                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
596
19
                        " bytes, but found ", ai_to_string(dataURI.dataLength));
597
19
            }
598
1.09k
        } else { // assume raw data
599
54
            if (statedLength != dataURI.dataLength) {
600
53
                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
601
53
                        " bytes, but found ", ai_to_string(dataURI.dataLength));
602
53
            }
603
604
1
            this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
605
1
            memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
606
1
        }
607
1.15k
    } else { // Local file
608
324
        if (byteLength > 0) {
609
302
            std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir.back() == '/' ? r.mCurrentAssetDir : r.mCurrentAssetDir + '/') : "";
610
611
302
            IOStream *file = r.OpenFile(dir + uri, "rb");
612
302
            if (file) {
613
36
                bool ok = LoadFromStream(*file, byteLength);
614
36
                delete file;
615
616
36
                if (!ok)
617
0
                    throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
618
266
            } else {
619
266
                throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
620
266
            }
621
302
        }
622
324
    }
623
1.47k
}
624
625
3.56k
inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
626
3.56k
    byteLength = length ? length : stream.FileSize();
627
628
3.56k
    if (byteLength > stream.FileSize()) {
629
108
        throw DeadlyImportError("GLTF: Invalid byteLength exceeds size of actual data.");
630
108
    }
631
632
3.46k
    if (baseOffset) {
633
3.43k
        stream.Seek(baseOffset, aiOrigin_SET);
634
3.43k
    }
635
636
3.46k
    mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
637
638
3.46k
    if (stream.Read(mData.get(), byteLength, 1) != 1) {
639
27
        return false;
640
27
    }
641
3.43k
    return true;
642
3.46k
}
643
644
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) {
645
0
    // Check pointer to data
646
0
    if (pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
647
0
648
0
    // Check offset
649
0
    if (pOffset > byteLength) {
650
0
        const uint8_t val_size = 32;
651
0
652
0
        char val[val_size];
653
0
654
0
        ai_snprintf(val, val_size, AI_SIZEFMT, pOffset);
655
0
        throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region.");
656
0
    }
657
0
658
0
    // Check length
659
0
    if ((pOffset + pEncodedData_Length) > byteLength) {
660
0
        const uint8_t val_size = 64;
661
0
662
0
        char val[val_size];
663
0
664
0
        ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length);
665
0
        throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range.");
666
0
    }
667
0
668
0
    // Add new region
669
0
    EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
670
0
    // And set new value for "byteLength"
671
0
    byteLength += (pDecodedData_Length - pEncodedData_Length);
672
0
}
673
674
0
inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
675
0
    if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) {
676
0
        return;
677
0
    }
678
0
679
0
    for (SEncodedRegion *reg : EncodedRegion_List) {
680
0
        if (reg->ID == pID) {
681
0
            EncodedRegion_Current = reg;
682
0
            return;
683
0
        }
684
0
    }
685
0
686
0
    throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found.");
687
0
}
688
689
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) {
690
0
    if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) {
691
0
        return false;
692
0
    }
693
0
694
0
    const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
695
0
    uint8_t *new_data = new uint8_t[new_data_size];
696
0
    // Copy data which place before replacing part.
697
0
    ::memcpy(new_data, mData.get(), pBufferData_Offset);
698
0
    // Copy new data.
699
0
    ::memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
700
0
    // Copy data which place after replacing part.
701
0
    ::memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
702
0
    // Apply new data
703
0
    mData.reset(new_data, std::default_delete<uint8_t[]>());
704
0
    byteLength = new_data_size;
705
0
706
0
    return true;
707
0
}
708
709
0
inline bool Buffer::ReplaceData_joint(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
710
0
    if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) {
711
0
        return false;
712
0
    }
713
0
714
0
    const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
715
0
    uint8_t *new_data = new uint8_t[new_data_size];
716
0
    // Copy data which place before replacing part.
717
0
    memcpy(new_data, mData.get(), pBufferData_Offset);
718
0
    // Copy new data.
719
0
    memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
720
0
    // Copy data which place after replacing part.
721
0
    memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], new_data_size - (pBufferData_Offset + pReplace_Count));
722
0
    // Apply new data
723
0
    mData.reset(new_data, std::default_delete<uint8_t[]>());
724
0
    byteLength = new_data_size;
725
0
726
0
    return true;
727
0
}
728
729
0
inline size_t Buffer::AppendData(uint8_t *data, size_t length) {
730
0
    const size_t offset = this->byteLength;
731
0
732
0
    // Force alignment to 4 bits
733
0
    const size_t paddedLength = (length + 3) & ~3;
734
0
    Grow(paddedLength);
735
0
    memcpy(mData.get() + offset, data, length);
736
0
    memset(mData.get() + offset + length, 0, paddedLength - length);
737
0
    return offset;
738
0
}
739
740
0
inline void Buffer::Grow(size_t amount) {
741
0
    if (amount <= 0) {
742
0
        return;
743
0
    }
744
0
745
0
    // Capacity is big enough
746
0
    if (capacity >= byteLength + amount) {
747
0
        byteLength += amount;
748
0
        return;
749
0
    }
750
0
751
0
    // Just allocate data which we need
752
0
    capacity = byteLength + amount;
753
0
754
0
    uint8_t *b = new uint8_t[capacity];
755
0
    if (nullptr != mData) {
756
0
        memcpy(b, mData.get(), byteLength);
757
0
    }
758
0
    mData.reset(b, std::default_delete<uint8_t[]>());
759
0
    byteLength += amount;
760
0
}
761
762
//
763
// struct BufferView
764
//
765
14.7k
inline void BufferView::Read(Value &obj, Asset &r) {
766
14.7k
    if (Value *bufferVal = FindUInt(obj, "buffer")) {
767
14.7k
        buffer = r.buffers.Retrieve(bufferVal->GetUint());
768
14.7k
    }
769
770
14.7k
    if (!buffer) {
771
14
        throw DeadlyImportError("GLTF: Buffer view without valid buffer.");
772
14
    }
773
774
14.7k
    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
775
14.7k
    byteLength = MemberOrDefault(obj, "byteLength", size_t(0));
776
14.7k
    byteStride = MemberOrDefault(obj, "byteStride", 0u);
777
778
    // Check length
779
14.7k
    if ((byteOffset + byteLength) > buffer->byteLength) {
780
64
        throw DeadlyImportError("GLTF: Buffer view with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
781
64
    }
782
14.7k
}
783
784
0
inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) {
785
0
    if (!buffer) {
786
0
        outTailSize = 0;
787
0
        return nullptr;
788
0
    }
789
0
    uint8_t * const basePtr = buffer->GetPointer();
790
0
    if (!basePtr) {
791
0
        outTailSize = 0;
792
0
        return nullptr;
793
0
    }
794
795
0
    size_t offset = accOffset + byteOffset;
796
0
    if (buffer->EncodedRegion_Current != nullptr) {
797
0
        const size_t begin = buffer->EncodedRegion_Current->Offset;
798
0
        const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
799
0
        if ((offset >= begin) && (offset < end)) {
800
0
            outTailSize = end - offset;
801
0
            return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
802
0
        }
803
0
    }
804
805
0
    if (offset >= buffer->byteLength) {
806
0
        outTailSize = 0;
807
0
        return nullptr;
808
0
    }
809
810
0
    outTailSize = buffer->byteLength - offset;
811
0
    return basePtr + offset;
812
0
}
813
814
//
815
// struct Accessor
816
//
817
0
inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) {
818
0
    if (bytes) {
819
0
        data.assign(bytes, bytes + numBytes);
820
0
    } else {
821
0
        data.resize(numBytes, 0x00);
822
0
    }
823
0
}
824
825
0
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
826
0
    size_t indicesTailDataSize;
827
0
    uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize);
828
0
    const unsigned int indexSize = int(ComponentTypeSize(indicesType));
829
0
    uint8_t *indicesEnd = pIndices + count * indexSize;
830
831
0
    if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) {
832
0
        throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
833
0
    }
834
835
0
    size_t valuesTailDataSize;
836
0
    uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize);
837
838
0
    if (elementSize * count > valuesTailDataSize) {
839
0
        throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
840
0
    }
841
0
    while (pIndices != indicesEnd) {
842
0
        size_t offset;
843
0
        switch (indicesType) {
844
0
        case ComponentType_UNSIGNED_BYTE:
845
0
            offset = *pIndices;
846
0
            break;
847
0
        case ComponentType_UNSIGNED_SHORT:
848
0
            offset = *reinterpret_cast<uint16_t *>(pIndices);
849
0
            break;
850
0
        case ComponentType_UNSIGNED_INT:
851
0
            offset = *reinterpret_cast<uint32_t *>(pIndices);
852
0
            break;
853
0
        default:
854
            // have fun with float and negative values from signed types as indices.
855
0
            throw DeadlyImportError("Unsupported component type in index.");
856
0
        }
857
858
0
        offset *= elementSize;
859
860
0
        if (offset + elementSize > data.size()) {
861
0
            throw DeadlyImportError("Invalid sparse accessor. Byte offset for patching points outside allocated memory.");
862
0
        }
863
864
0
        std::memcpy(data.data() + offset, pValues, elementSize);
865
866
0
        pValues += elementSize;
867
0
        pIndices += indexSize;
868
0
    }
869
0
}
870
871
20.5k
inline void Accessor::Read(Value &obj, Asset &r) {
872
20.5k
    if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
873
15.6k
        bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
874
15.6k
    }
875
876
20.5k
    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
877
20.5k
    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
878
20.5k
    {
879
20.5k
        const Value *countValue = FindUInt(obj, "count");
880
20.5k
        if (!countValue) {
881
24
            throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
882
24
        }
883
20.5k
        count = countValue->GetUint();
884
20.5k
    }
885
886
0
    const char *typestr;
887
20.5k
    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
888
889
20.5k
    if (bufferView) {
890
        // Check length
891
14.9k
        unsigned long long byteLength = count > 0
892
14.9k
            ? (unsigned long long)GetStride() * (unsigned long long)(count - 1) + (unsigned long long)GetElementSize()
893
14.9k
            : 0;
894
895
        // handle integer overflow
896
14.9k
        if (byteLength < count) {
897
0
            throw DeadlyImportError("GLTF: Accessor with offset/count (", byteOffset, "/", count, ") is out of range.");
898
0
        }
899
900
14.9k
        if ((byteOffset + byteLength) > bufferView->byteLength || (bufferView->byteOffset + byteOffset + byteLength) > bufferView->buffer->byteLength) {
901
107
            throw DeadlyImportError("GLTF: Accessor with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
902
107
        }
903
14.9k
    }
904
905
20.4k
    if (Value *sparseValue = FindObject(obj, "sparse")) {
906
0
        sparse.reset(new Sparse);
907
        // count
908
0
        ReadMember(*sparseValue, "count", sparse->count);
909
910
        // indices
911
0
        if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
912
            //indices bufferView
913
0
            Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
914
0
            if (!indiceViewID) {
915
0
                throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
916
0
            }
917
0
            sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
918
            //indices byteOffset
919
0
            sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
920
            //indices componentType
921
0
            sparse->indicesType = MemberOrDefault(*indicesValue, "componentType", ComponentType_BYTE);
922
            //sparse->indices->Read(*indicesValue, r);
923
0
        } else {
924
            // indicesType
925
0
            sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT);
926
0
        }
927
928
        // value
929
0
        if (Value *valuesValue = FindObject(*sparseValue, "values")) {
930
            //value bufferView
931
0
            Value *valueViewID = FindUInt(*valuesValue, "bufferView");
932
0
            if (!valueViewID) {
933
0
                throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
934
0
            }
935
0
            sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
936
            //value byteOffset
937
0
            sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
938
            //sparse->values->Read(*valuesValue, r);
939
0
        }
940
941
942
0
        const unsigned int elementSize = GetElementSize();
943
0
        const size_t dataSize = count * elementSize;
944
0
        if (bufferView) {
945
0
            size_t bufferViewTailSize;
946
0
            const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
947
0
            if (dataSize > bufferViewTailSize) {
948
0
                throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
949
0
            }
950
0
            sparse->PopulateData(dataSize, bufferViewPointer);
951
0
        }
952
0
        else {
953
0
            sparse->PopulateData(dataSize, nullptr);
954
0
        }
955
0
        sparse->PatchData(elementSize);
956
0
    }
957
20.4k
}
958
959
50.1k
inline unsigned int Accessor::GetNumComponents() {
960
50.1k
    return AttribType::GetNumComponents(type);
961
50.1k
}
962
963
49.1k
inline unsigned int Accessor::GetBytesPerComponent() {
964
49.1k
    return int(ComponentTypeSize(componentType));
965
49.1k
}
966
967
49.1k
inline unsigned int Accessor::GetElementSize() {
968
49.1k
    return GetNumComponents() * GetBytesPerComponent();
969
49.1k
}
970
971
12.9k
inline uint8_t *Accessor::GetPointer() {
972
12.9k
    if (decodedBuffer)
973
0
        return decodedBuffer->GetPointer();
974
975
12.9k
    if (sparse)
976
0
        return sparse->data.data();
977
978
12.9k
    if (!bufferView || !bufferView->buffer) return nullptr;
979
12.7k
    uint8_t *basePtr = bufferView->buffer->GetPointer();
980
12.7k
    if (!basePtr) return nullptr;
981
982
12.7k
    size_t offset = byteOffset + bufferView->byteOffset;
983
984
    // Check if region is encoded.
985
12.7k
    if (bufferView->buffer->EncodedRegion_Current != nullptr) {
986
0
        const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
987
0
        const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
988
989
0
        if ((offset >= begin) && (offset < end))
990
0
            return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
991
0
    }
992
993
12.7k
    return basePtr + offset;
994
12.7k
}
995
996
27.7k
inline size_t Accessor::GetStride() {
997
    // Decoded buffer is always packed
998
27.7k
    if (decodedBuffer)
999
0
        return GetElementSize();
1000
1001
    // Sparse and normal bufferView
1002
27.7k
    return (bufferView && bufferView->byteStride ? bufferView->byteStride : GetElementSize());
1003
27.7k
}
1004
1005
70.3k
inline size_t Accessor::GetMaxByteSize() {
1006
70.3k
    if (decodedBuffer)
1007
0
        return decodedBuffer->byteLength;
1008
1009
70.3k
    if (sparse) {
1010
0
        return sparse->data.size();
1011
0
    }
1012
1013
70.3k
    if (bufferView) {
1014
70.3k
        return byteOffset <= bufferView->byteLength ? bufferView->byteLength - byteOffset : 0;
1015
70.3k
    }
1016
1017
0
    return 0;
1018
70.3k
}
1019
1020
template <class T>
1021
10.4k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
10.4k
    uint8_t *data = GetPointer();
1023
10.4k
    if (!data) {
1024
107
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
107
    }
1026
1027
10.3k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
10.3k
    const size_t elemSize = GetElementSize();
1029
10.3k
    const size_t totalSize = elemSize * usedCount;
1030
1031
10.3k
    const size_t stride = GetStride();
1032
1033
10.3k
    const size_t targetElemSize = sizeof(T);
1034
1035
10.3k
    if (elemSize > targetElemSize) {
1036
38
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
38
    }
1038
1039
10.3k
    const size_t maxSize = GetMaxByteSize();
1040
1041
10.3k
    if (elemSize > maxSize) {
1042
7
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
7
    }
1044
1045
10.3k
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
10.3k
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
10.3k
    outData = new T[usedCount];
1052
1053
10.3k
    if (remappingIndices != nullptr) {
1054
45.4k
        for (size_t i = 0; i < usedCount; ++i) {
1055
38.4k
            size_t srcIdx = (*remappingIndices)[i];
1056
38.4k
            if (srcIdx >= count) {
1057
5
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
5
            }
1059
38.4k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
38.4k
        }
1061
7.03k
    } else { // non-indexed cases
1062
3.30k
        if (stride == elemSize && targetElemSize == elemSize) {
1063
1.48k
            memcpy(outData, data, totalSize);
1064
1.81k
        } else {
1065
65.5k
            for (size_t i = 0; i < usedCount; ++i) {
1066
63.7k
                memcpy(outData + i, data + i * stride, elemSize);
1067
63.7k
            }
1068
1.81k
        }
1069
3.30k
    }
1070
10.3k
    return usedCount;
1071
10.3k
}
glTF2Importer.cpp:unsigned long glTF2::Accessor::ExtractData<BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Weights>(BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Weights*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
1.38k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
1.38k
    uint8_t *data = GetPointer();
1023
1.38k
    if (!data) {
1024
10
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
10
    }
1026
1027
1.37k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
1.37k
    const size_t elemSize = GetElementSize();
1029
1.37k
    const size_t totalSize = elemSize * usedCount;
1030
1031
1.37k
    const size_t stride = GetStride();
1032
1033
1.37k
    const size_t targetElemSize = sizeof(T);
1034
1035
1.37k
    if (elemSize > targetElemSize) {
1036
2
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
2
    }
1038
1039
1.37k
    const size_t maxSize = GetMaxByteSize();
1040
1041
1.37k
    if (elemSize > maxSize) {
1042
2
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
2
    }
1044
1045
1.37k
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
1.37k
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
1.37k
    outData = new T[usedCount];
1052
1053
1.37k
    if (remappingIndices != nullptr) {
1054
5.11k
        for (size_t i = 0; i < usedCount; ++i) {
1055
4.03k
            size_t srcIdx = (*remappingIndices)[i];
1056
4.03k
            if (srcIdx >= count) {
1057
1
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
1
            }
1059
4.03k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
4.03k
        }
1061
1.08k
    } else { // non-indexed cases
1062
293
        if (stride == elemSize && targetElemSize == elemSize) {
1063
229
            memcpy(outData, data, totalSize);
1064
229
        } else {
1065
354
            for (size_t i = 0; i < usedCount; ++i) {
1066
290
                memcpy(outData + i, data + i * stride, elemSize);
1067
290
            }
1068
64
        }
1069
293
    }
1070
1.37k
    return usedCount;
1071
1.37k
}
glTF2Importer.cpp:unsigned long glTF2::Accessor::ExtractData<BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Indices8>(BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Indices8*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
154
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
154
    uint8_t *data = GetPointer();
1023
154
    if (!data) {
1024
16
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
16
    }
1026
1027
138
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
138
    const size_t elemSize = GetElementSize();
1029
138
    const size_t totalSize = elemSize * usedCount;
1030
1031
138
    const size_t stride = GetStride();
1032
1033
138
    const size_t targetElemSize = sizeof(T);
1034
1035
138
    if (elemSize > targetElemSize) {
1036
16
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
16
    }
1038
1039
122
    const size_t maxSize = GetMaxByteSize();
1040
1041
122
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
122
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
122
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
122
    outData = new T[usedCount];
1052
1053
122
    if (remappingIndices != nullptr) {
1054
305
        for (size_t i = 0; i < usedCount; ++i) {
1055
254
            size_t srcIdx = (*remappingIndices)[i];
1056
254
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
254
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
254
        }
1061
71
    } else { // non-indexed cases
1062
71
        if (stride == elemSize && targetElemSize == elemSize) {
1063
43
            memcpy(outData, data, totalSize);
1064
43
        } else {
1065
176
            for (size_t i = 0; i < usedCount; ++i) {
1066
148
                memcpy(outData + i, data + i * stride, elemSize);
1067
148
            }
1068
28
        }
1069
71
    }
1070
122
    return usedCount;
1071
122
}
glTF2Importer.cpp:unsigned long glTF2::Accessor::ExtractData<BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Indices16>(BuildVertexWeightMapping(glTF2::Mesh::Primitive&, std::__1::vector<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> >, std::__1::allocator<std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > > >&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >*)::Indices16*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
1.16k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
1.16k
    uint8_t *data = GetPointer();
1023
1.16k
    if (!data) {
1024
17
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
17
    }
1026
1027
1.14k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
1.14k
    const size_t elemSize = GetElementSize();
1029
1.14k
    const size_t totalSize = elemSize * usedCount;
1030
1031
1.14k
    const size_t stride = GetStride();
1032
1033
1.14k
    const size_t targetElemSize = sizeof(T);
1034
1035
1.14k
    if (elemSize > targetElemSize) {
1036
8
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
8
    }
1038
1039
1.13k
    const size_t maxSize = GetMaxByteSize();
1040
1041
1.13k
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
1.13k
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
1.13k
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
1.13k
    outData = new T[usedCount];
1052
1053
1.13k
    if (remappingIndices != nullptr) {
1054
4.48k
        for (size_t i = 0; i < usedCount; ++i) {
1055
3.52k
            size_t srcIdx = (*remappingIndices)[i];
1056
3.52k
            if (srcIdx >= count) {
1057
4
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
4
            }
1059
3.52k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
3.52k
        }
1061
962
    } else { // non-indexed cases
1062
174
        if (stride == elemSize && targetElemSize == elemSize) {
1063
123
            memcpy(outData, data, totalSize);
1064
123
        } else {
1065
315
            for (size_t i = 0; i < usedCount; ++i) {
1066
264
                memcpy(outData + i, data + i * stride, elemSize);
1067
264
            }
1068
51
        }
1069
174
    }
1070
1.13k
    return usedCount;
1071
1.13k
}
unsigned long glTF2::Accessor::ExtractData<aiVector3t<float> >(aiVector3t<float>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
6.52k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
6.52k
    uint8_t *data = GetPointer();
1023
6.52k
    if (!data) {
1024
32
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
32
    }
1026
1027
6.48k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
6.48k
    const size_t elemSize = GetElementSize();
1029
6.48k
    const size_t totalSize = elemSize * usedCount;
1030
1031
6.48k
    const size_t stride = GetStride();
1032
1033
6.48k
    const size_t targetElemSize = sizeof(T);
1034
1035
6.48k
    if (elemSize > targetElemSize) {
1036
4
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
4
    }
1038
1039
6.48k
    const size_t maxSize = GetMaxByteSize();
1040
1041
6.48k
    if (elemSize > maxSize) {
1042
2
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
2
    }
1044
1045
6.48k
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
6.48k
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
6.48k
    outData = new T[usedCount];
1052
1053
6.48k
    if (remappingIndices != nullptr) {
1054
33.8k
        for (size_t i = 0; i < usedCount; ++i) {
1055
29.2k
            size_t srcIdx = (*remappingIndices)[i];
1056
29.2k
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
29.2k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
29.2k
        }
1061
4.56k
    } else { // non-indexed cases
1062
1.91k
        if (stride == elemSize && targetElemSize == elemSize) {
1063
573
            memcpy(outData, data, totalSize);
1064
1.34k
        } else {
1065
59.1k
            for (size_t i = 0; i < usedCount; ++i) {
1066
57.8k
                memcpy(outData + i, data + i * stride, elemSize);
1067
57.8k
            }
1068
1.34k
        }
1069
1.91k
    }
1070
6.48k
    return usedCount;
1071
6.48k
}
glTF2Importer.cpp:unsigned long glTF2::Accessor::ExtractData<(anonymous namespace)::Tangent>((anonymous namespace)::Tangent*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
41
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
41
    uint8_t *data = GetPointer();
1023
41
    if (!data) {
1024
2
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
2
    }
1026
1027
39
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
39
    const size_t elemSize = GetElementSize();
1029
39
    const size_t totalSize = elemSize * usedCount;
1030
1031
39
    const size_t stride = GetStride();
1032
1033
39
    const size_t targetElemSize = sizeof(T);
1034
1035
39
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
39
    const size_t maxSize = GetMaxByteSize();
1040
1041
39
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
39
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
39
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
39
    outData = new T[usedCount];
1052
1053
39
    if (remappingIndices != nullptr) {
1054
188
        for (size_t i = 0; i < usedCount; ++i) {
1055
161
            size_t srcIdx = (*remappingIndices)[i];
1056
161
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
161
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
161
        }
1061
27
    } else { // non-indexed cases
1062
12
        if (stride == elemSize && targetElemSize == elemSize) {
1063
2
            memcpy(outData, data, totalSize);
1064
10
        } else {
1065
250
            for (size_t i = 0; i < usedCount; ++i) {
1066
240
                memcpy(outData + i, data + i * stride, elemSize);
1067
240
            }
1068
10
        }
1069
12
    }
1070
39
    return usedCount;
1071
39
}
unsigned long glTF2::Accessor::ExtractData<aiColor4t<float> >(aiColor4t<float>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
422
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
422
    uint8_t *data = GetPointer();
1023
422
    if (!data) {
1024
5
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
5
    }
1026
1027
417
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
417
    const size_t elemSize = GetElementSize();
1029
417
    const size_t totalSize = elemSize * usedCount;
1030
1031
417
    const size_t stride = GetStride();
1032
1033
417
    const size_t targetElemSize = sizeof(T);
1034
1035
417
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
417
    const size_t maxSize = GetMaxByteSize();
1040
1041
417
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
417
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
417
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
417
    outData = new T[usedCount];
1052
1053
417
    if (remappingIndices != nullptr) {
1054
1.49k
        for (size_t i = 0; i < usedCount; ++i) {
1055
1.16k
            size_t srcIdx = (*remappingIndices)[i];
1056
1.16k
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
1.16k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
1.16k
        }
1061
332
    } else { // non-indexed cases
1062
85
        if (stride == elemSize && targetElemSize == elemSize) {
1063
51
            memcpy(outData, data, totalSize);
1064
51
        } else {
1065
728
            for (size_t i = 0; i < usedCount; ++i) {
1066
694
                memcpy(outData + i, data + i * stride, elemSize);
1067
694
            }
1068
34
        }
1069
85
    }
1070
417
    return usedCount;
1071
417
}
unsigned long glTF2::Accessor::ExtractData<aiColor4t<unsigned char> >(aiColor4t<unsigned char>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
14
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
14
    uint8_t *data = GetPointer();
1023
14
    if (!data) {
1024
2
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
2
    }
1026
1027
12
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
12
    const size_t elemSize = GetElementSize();
1029
12
    const size_t totalSize = elemSize * usedCount;
1030
1031
12
    const size_t stride = GetStride();
1032
1033
12
    const size_t targetElemSize = sizeof(T);
1034
1035
12
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
12
    const size_t maxSize = GetMaxByteSize();
1040
1041
12
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
12
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
12
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
12
    outData = new T[usedCount];
1052
1053
12
    if (remappingIndices != nullptr) {
1054
13
        for (size_t i = 0; i < usedCount; ++i) {
1055
9
            size_t srcIdx = (*remappingIndices)[i];
1056
9
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
9
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
9
        }
1061
8
    } else { // non-indexed cases
1062
8
        if (stride == elemSize && targetElemSize == elemSize) {
1063
2
            memcpy(outData, data, totalSize);
1064
6
        } else {
1065
30
            for (size_t i = 0; i < usedCount; ++i) {
1066
24
                memcpy(outData + i, data + i * stride, elemSize);
1067
24
            }
1068
6
        }
1069
8
    }
1070
12
    return usedCount;
1071
12
}
unsigned long glTF2::Accessor::ExtractData<aiColor4t<unsigned short> >(aiColor4t<unsigned short>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
21
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
21
    uint8_t *data = GetPointer();
1023
21
    if (!data) {
1024
2
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
2
    }
1026
1027
19
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
19
    const size_t elemSize = GetElementSize();
1029
19
    const size_t totalSize = elemSize * usedCount;
1030
1031
19
    const size_t stride = GetStride();
1032
1033
19
    const size_t targetElemSize = sizeof(T);
1034
1035
19
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
19
    const size_t maxSize = GetMaxByteSize();
1040
1041
19
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
19
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
19
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
19
    outData = new T[usedCount];
1052
1053
19
    if (remappingIndices != nullptr) {
1054
28
        for (size_t i = 0; i < usedCount; ++i) {
1055
18
            size_t srcIdx = (*remappingIndices)[i];
1056
18
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
18
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
18
        }
1061
10
    } else { // non-indexed cases
1062
9
        if (stride == elemSize && targetElemSize == elemSize) {
1063
5
            memcpy(outData, data, totalSize);
1064
5
        } else {
1065
20
            for (size_t i = 0; i < usedCount; ++i) {
1066
16
                memcpy(outData + i, data + i * stride, elemSize);
1067
16
            }
1068
4
        }
1069
9
    }
1070
19
    return usedCount;
1071
19
}
unsigned long glTF2::Accessor::ExtractData<float [16]>(float (*&) [16], std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
542
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
542
    uint8_t *data = GetPointer();
1023
542
    if (!data) {
1024
16
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
16
    }
1026
1027
526
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
526
    const size_t elemSize = GetElementSize();
1029
526
    const size_t totalSize = elemSize * usedCount;
1030
1031
526
    const size_t stride = GetStride();
1032
1033
526
    const size_t targetElemSize = sizeof(T);
1034
1035
526
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
526
    const size_t maxSize = GetMaxByteSize();
1040
1041
526
    if (elemSize > maxSize) {
1042
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
0
    }
1044
1045
526
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
526
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
526
    outData = new T[usedCount];
1052
1053
526
    if (remappingIndices != nullptr) {
1054
0
        for (size_t i = 0; i < usedCount; ++i) {
1055
0
            size_t srcIdx = (*remappingIndices)[i];
1056
0
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
0
        }
1061
526
    } else { // non-indexed cases
1062
526
        if (stride == elemSize && targetElemSize == elemSize) {
1063
370
            memcpy(outData, data, totalSize);
1064
370
        } else {
1065
2.08k
            for (size_t i = 0; i < usedCount; ++i) {
1066
1.92k
                memcpy(outData + i, data + i * stride, elemSize);
1067
1.92k
            }
1068
156
        }
1069
526
    }
1070
526
    return usedCount;
1071
526
}
unsigned long glTF2::Accessor::ExtractData<float>(float*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
117
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
117
    uint8_t *data = GetPointer();
1023
117
    if (!data) {
1024
1
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
1
    }
1026
1027
116
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
116
    const size_t elemSize = GetElementSize();
1029
116
    const size_t totalSize = elemSize * usedCount;
1030
1031
116
    const size_t stride = GetStride();
1032
1033
116
    const size_t targetElemSize = sizeof(T);
1034
1035
116
    if (elemSize > targetElemSize) {
1036
6
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
6
    }
1038
1039
110
    const size_t maxSize = GetMaxByteSize();
1040
1041
110
    if (elemSize > maxSize) {
1042
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
1
    }
1044
1045
109
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
109
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
109
    outData = new T[usedCount];
1052
1053
109
    if (remappingIndices != nullptr) {
1054
0
        for (size_t i = 0; i < usedCount; ++i) {
1055
0
            size_t srcIdx = (*remappingIndices)[i];
1056
0
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
0
        }
1061
109
    } else { // non-indexed cases
1062
109
        if (stride == elemSize && targetElemSize == elemSize) {
1063
75
            memcpy(outData, data, totalSize);
1064
75
        } else {
1065
520
            for (size_t i = 0; i < usedCount; ++i) {
1066
486
                memcpy(outData + i, data + i * stride, elemSize);
1067
486
            }
1068
34
        }
1069
109
    }
1070
109
    return usedCount;
1071
109
}
unsigned long glTF2::Accessor::ExtractData<vec4f>(vec4f*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
43
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
43
    uint8_t *data = GetPointer();
1023
43
    if (!data) {
1024
3
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
3
    }
1026
1027
40
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
40
    const size_t elemSize = GetElementSize();
1029
40
    const size_t totalSize = elemSize * usedCount;
1030
1031
40
    const size_t stride = GetStride();
1032
1033
40
    const size_t targetElemSize = sizeof(T);
1034
1035
40
    if (elemSize > targetElemSize) {
1036
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
1
    }
1038
1039
39
    const size_t maxSize = GetMaxByteSize();
1040
1041
39
    if (elemSize > maxSize) {
1042
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
1
    }
1044
1045
38
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
38
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
38
    outData = new T[usedCount];
1052
1053
38
    if (remappingIndices != nullptr) {
1054
0
        for (size_t i = 0; i < usedCount; ++i) {
1055
0
            size_t srcIdx = (*remappingIndices)[i];
1056
0
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
0
        }
1061
38
    } else { // non-indexed cases
1062
38
        if (stride == elemSize && targetElemSize == elemSize) {
1063
2
            memcpy(outData, data, totalSize);
1064
36
        } else {
1065
1.04k
            for (size_t i = 0; i < usedCount; ++i) {
1066
1.01k
                memcpy(outData + i, data + i * stride, elemSize);
1067
1.01k
            }
1068
36
        }
1069
38
    }
1070
38
    return usedCount;
1071
38
}
unsigned long glTF2::Accessor::ExtractData<aiQuaterniont<float> >(aiQuaterniont<float>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
64
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
64
    uint8_t *data = GetPointer();
1023
64
    if (!data) {
1024
1
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
1
    }
1026
1027
63
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
63
    const size_t elemSize = GetElementSize();
1029
63
    const size_t totalSize = elemSize * usedCount;
1030
1031
63
    const size_t stride = GetStride();
1032
1033
63
    const size_t targetElemSize = sizeof(T);
1034
1035
63
    if (elemSize > targetElemSize) {
1036
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
1
    }
1038
1039
62
    const size_t maxSize = GetMaxByteSize();
1040
1041
62
    if (elemSize > maxSize) {
1042
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1043
1
    }
1044
1045
61
    const size_t maxCount = (maxSize - elemSize) / stride + 1;
1046
1047
61
    if (count > maxCount) {
1048
0
        throw DeadlyImportError("GLTF: count ", count, " > maxCount ", maxCount, " in ", getContextForErrorMessages(id, name));
1049
0
    }
1050
1051
61
    outData = new T[usedCount];
1052
1053
61
    if (remappingIndices != nullptr) {
1054
0
        for (size_t i = 0; i < usedCount; ++i) {
1055
0
            size_t srcIdx = (*remappingIndices)[i];
1056
0
            if (srcIdx >= count) {
1057
0
                throw DeadlyImportError("GLTF: index ", srcIdx, " >= count ", count, " in ", getContextForErrorMessages(id, name));
1058
0
            }
1059
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1060
0
        }
1061
61
    } else { // non-indexed cases
1062
61
        if (stride == elemSize && targetElemSize == elemSize) {
1063
11
            memcpy(outData, data, totalSize);
1064
50
        } else {
1065
893
            for (size_t i = 0; i < usedCount; ++i) {
1066
843
                memcpy(outData + i, data + i * stride, elemSize);
1067
843
            }
1068
50
        }
1069
61
    }
1070
61
    return usedCount;
1071
61
}
1072
1073
0
inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) {
1074
0
    uint8_t *buffer_ptr = bufferView->buffer->GetPointer();
1075
0
    size_t offset = byteOffset + bufferView->byteOffset;
1076
0
1077
0
    size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
1078
0
1079
0
    const uint8_t *src = reinterpret_cast<const uint8_t *>(src_buffer);
1080
0
    uint8_t *dst = reinterpret_cast<uint8_t *>(buffer_ptr + offset);
1081
0
1082
0
    ai_assert(dst + _count * dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
1083
0
    CopyData(_count, src, src_stride, dst, dst_stride);
1084
0
}
1085
1086
0
inline void Accessor::WriteSparseValues(size_t _count, const void *src_data, size_t src_dataStride) {
1087
0
    if (!sparse)
1088
0
        return;
1089
0
1090
0
    // values
1091
0
    uint8_t *value_buffer_ptr = sparse->values->buffer->GetPointer();
1092
0
    size_t value_offset = sparse->valuesByteOffset + sparse->values->byteOffset;
1093
0
    size_t value_dst_stride = GetNumComponents() * GetBytesPerComponent();
1094
0
    const uint8_t *value_src = reinterpret_cast<const uint8_t *>(src_data);
1095
0
    uint8_t *value_dst = reinterpret_cast<uint8_t *>(value_buffer_ptr + value_offset);
1096
0
    ai_assert(value_dst + _count * value_dst_stride <= value_buffer_ptr + sparse->values->buffer->byteLength);
1097
0
    CopyData(_count, value_src, src_dataStride, value_dst, value_dst_stride);
1098
0
}
1099
1100
0
inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, size_t src_idxStride) {
1101
0
    if (!sparse)
1102
0
        return;
1103
0
1104
0
    // indices
1105
0
    uint8_t *indices_buffer_ptr = sparse->indices->buffer->GetPointer();
1106
0
    size_t indices_offset = sparse->indicesByteOffset + sparse->indices->byteOffset;
1107
0
    size_t indices_dst_stride = 1 * sizeof(unsigned short);
1108
0
    const uint8_t *indices_src = reinterpret_cast<const uint8_t *>(src_idx);
1109
0
    uint8_t *indices_dst = reinterpret_cast<uint8_t *>(indices_buffer_ptr + indices_offset);
1110
0
    ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
1111
0
    CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
1112
0
}
1113
1114
inline Accessor::Indexer::Indexer(Accessor &acc) :
1115
2.47k
    accessor(acc),
1116
2.47k
    data(acc.GetPointer()),
1117
2.47k
    elemSize(acc.GetElementSize()),
1118
2.47k
    stride(acc.GetStride()) {
1119
2.47k
}
1120
1121
//! Accesses the i-th value as defined by the accessor
1122
template <class T>
1123
59.9k
T Accessor::Indexer::GetValue(int i) {
1124
59.9k
    ai_assert(data);
1125
59.9k
    if (i * stride >= accessor.GetMaxByteSize()) {
1126
1
        throw DeadlyImportError("GLTF: Invalid index ", i, ", count out of range for buffer with stride ", stride, " and size ", accessor.GetMaxByteSize(), ".");
1127
1
    }
1128
    // Ensure that the memcpy doesn't overwrite the local.
1129
59.9k
    const size_t sizeToCopy = std::min(elemSize, sizeof(T));
1130
59.9k
    T value = T();
1131
    // Assume platform endianness matches GLTF binary data (which is little-endian).
1132
59.9k
    memcpy(&value, data + i * stride, sizeToCopy);
1133
59.9k
    return value;
1134
59.9k
}
1135
1136
inline Image::Image() :
1137
220
        width(0),
1138
220
        height(0),
1139
220
        mDataLength(0) {
1140
220
}
1141
1142
220
inline void Image::Read(Value &obj, Asset &r) {
1143
    //basisu: no need to handle .ktx2, .basis, load as is
1144
220
    if (!mDataLength) {
1145
220
        Value *curUri = FindString(obj, "uri");
1146
220
        if (nullptr != curUri) {
1147
99
            const char *uristr = curUri->GetString();
1148
1149
99
            glTFCommon::Util::DataURI dataURI;
1150
99
            if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
1151
82
                mimeType = dataURI.mediaType;
1152
82
                if (dataURI.base64) {
1153
61
                    uint8_t *ptr = nullptr;
1154
61
                    mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr);
1155
61
                    mData.reset(ptr);
1156
61
                }
1157
82
            } else {
1158
17
                this->uri = uristr;
1159
17
            }
1160
121
        } else if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
1161
116
            this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
1162
116
            if (Value *mtype = FindString(obj, "mimeType")) {
1163
109
                this->mimeType = mtype->GetString();
1164
109
            }
1165
116
            if (!this->bufferView || this->mimeType.empty()) {
1166
2
                throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " does not have a URI, so it must have a valid bufferView and mimetype");
1167
2
            }
1168
1169
114
            Ref<Buffer> buffer = this->bufferView->buffer;
1170
1171
114
            this->mDataLength = this->bufferView->byteLength;
1172
            // maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
1173
1174
114
            this->mData.reset(new uint8_t[this->mDataLength]);
1175
114
            memcpy(this->mData.get(), buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
1176
114
        } else {
1177
5
            throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " should have either a URI of a bufferView and mimetype");
1178
5
        }
1179
220
    }
1180
220
}
1181
1182
130
inline uint8_t *Image::StealData() {
1183
130
    mDataLength = 0;
1184
130
    return mData.release();
1185
130
}
1186
1187
// Never take over the ownership of data whenever binary or not
1188
0
inline void Image::SetData(uint8_t *data, size_t length, Asset &r) {
1189
0
    Ref<Buffer> b = r.GetBodyBuffer();
1190
0
    if (b) { // binary file: append to body
1191
0
        std::string bvId = r.FindUniqueID(this->id, "imgdata");
1192
0
        bufferView = r.bufferViews.Create(bvId);
1193
0
1194
0
        bufferView->buffer = b;
1195
0
        bufferView->byteLength = length;
1196
0
        bufferView->byteOffset = b->AppendData(data, length);
1197
0
    } else { // text file: will be stored as a data uri
1198
0
        uint8_t *temp = new uint8_t[length];
1199
0
        memcpy(temp, data, length);
1200
0
        this->mData.reset(temp);
1201
0
        this->mDataLength = length;
1202
0
    }
1203
0
}
1204
1205
181
inline void Sampler::Read(Value &obj, Asset & /*r*/) {
1206
181
    SetDefaults();
1207
1208
181
    ReadMember(obj, "name", name);
1209
181
    ReadMember(obj, "magFilter", magFilter);
1210
181
    ReadMember(obj, "minFilter", minFilter);
1211
181
    ReadMember(obj, "wrapS", wrapS);
1212
181
    ReadMember(obj, "wrapT", wrapT);
1213
181
}
1214
1215
362
inline void Sampler::SetDefaults() {
1216
    //only wrapping modes have defaults
1217
362
    wrapS = SamplerWrap::Repeat;
1218
362
    wrapT = SamplerWrap::Repeat;
1219
362
    magFilter = SamplerMagFilter::UNSET;
1220
362
    minFilter = SamplerMinFilter::UNSET;
1221
362
}
1222
1223
271
inline void Texture::Read(Value &obj, Asset &r) {
1224
271
    if (Value *sourceVal = FindUInt(obj, "source")) {
1225
229
        source = r.images.Retrieve(sourceVal->GetUint());
1226
229
    }
1227
1228
271
    if (Value *samplerVal = FindUInt(obj, "sampler")) {
1229
189
        sampler = r.samplers.Retrieve(samplerVal->GetUint());
1230
189
    }
1231
1232
271
    if (Value *extensions = FindObject(obj, "extensions")) {
1233
0
        if (r.extensionsUsed.KHR_texture_basisu) {
1234
0
            if (Value *curBasisU = FindObject(*extensions, "KHR_texture_basisu")) {
1235
1236
0
                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
1237
0
                    source = r.images.Retrieve(sourceVal->GetUint());
1238
0
                }
1239
0
            }
1240
0
        } else if(r.extensionsUsed.EXT_texture_webp) {
1241
0
            if (Value *curBasisU = FindObject(*extensions, "EXT_texture_webp")) {
1242
1243
0
                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
1244
0
                    source = r.images.Retrieve(sourceVal->GetUint());
1245
0
                }
1246
0
            }
1247
0
        }
1248
0
    }
1249
271
}
1250
1251
354
void Material::SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
1252
354
    if (r.extensionsUsed.KHR_texture_transform) {
1253
3
        if (Value *pKHR_texture_transform = FindExtension(*prop, "KHR_texture_transform")) {
1254
0
            out.textureTransformSupported = true;
1255
0
            if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
1256
0
                out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
1257
0
                out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
1258
0
            } else {
1259
0
                out.TextureTransformExt_t.offset[0] = 0;
1260
0
                out.TextureTransformExt_t.offset[1] = 0;
1261
0
            }
1262
1263
0
            if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
1264
0
                out.TextureTransformExt_t.rotation = 0;
1265
0
            }
1266
1267
0
            if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
1268
0
                out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
1269
0
                out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
1270
0
            } else {
1271
0
                out.TextureTransformExt_t.scale[0] = 1;
1272
0
                out.TextureTransformExt_t.scale[1] = 1;
1273
0
            }
1274
0
        }
1275
3
    }
1276
1277
354
    if (Value *indexProp = FindUInt(*prop, "index")) {
1278
348
        out.texture = r.textures.Retrieve(indexProp->GetUint());
1279
348
    }
1280
1281
354
    if (Value *texcoord = FindUInt(*prop, "texCoord")) {
1282
2
        out.texCoord = texcoord->GetUint();
1283
2
    }
1284
354
}
1285
1286
12.0k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
1287
12.0k
    if (Value *prop = FindMember(vals, propName)) {
1288
354
        SetTextureProperties(r, prop, out);
1289
354
    }
1290
12.0k
}
1291
1292
4.63k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
1293
4.63k
    if (Value *prop = FindMember(vals, propName)) {
1294
0
        SetTextureProperties(r, prop, out);
1295
1296
0
        if (Value *scale = FindNumber(*prop, "scale")) {
1297
0
            out.scale = static_cast<float>(scale->GetDouble());
1298
0
        }
1299
0
    }
1300
4.63k
}
1301
1302
4.63k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
1303
4.63k
    if (Value *prop = FindMember(vals, propName)) {
1304
0
        SetTextureProperties(r, prop, out);
1305
1306
0
        if (Value *strength = FindNumber(*prop, "strength")) {
1307
0
            out.strength = static_cast<float>(strength->GetDouble());
1308
0
        }
1309
0
    }
1310
4.63k
}
1311
1312
4.67k
inline void Material::Read(Value &material, Asset &r) {
1313
4.67k
    SetDefaults();
1314
1315
4.67k
    if (Value *curPbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
1316
3.72k
        ReadMember(*curPbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
1317
3.72k
        ReadTextureProperty(r, *curPbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
1318
3.72k
        ReadTextureProperty(r, *curPbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
1319
3.72k
        ReadMember(*curPbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
1320
3.72k
        ReadMember(*curPbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
1321
3.72k
    }
1322
1323
4.67k
    ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
1324
4.67k
    ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
1325
4.67k
    ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
1326
4.67k
    ReadMember(material, "emissiveFactor", this->emissiveFactor);
1327
1328
4.67k
    ReadMember(material, "doubleSided", this->doubleSided);
1329
4.67k
    ReadMember(material, "alphaMode", this->alphaMode);
1330
4.67k
    ReadMember(material, "alphaCutoff", this->alphaCutoff);
1331
1332
4.67k
    if (Value *extensions = FindObject(material, "extensions")) {
1333
0
        if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
1334
0
            if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
1335
0
                PbrSpecularGlossiness pbrSG;
1336
1337
0
                ReadMember(*curPbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
1338
0
                ReadTextureProperty(r, *curPbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
1339
0
                ReadTextureProperty(r, *curPbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
1340
0
                ReadMember(*curPbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
1341
0
                ReadMember(*curPbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
1342
1343
0
                this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
1344
0
            }
1345
0
        }
1346
1347
0
        if (r.extensionsUsed.KHR_materials_specular) {
1348
0
            if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) {
1349
0
                MaterialSpecular specular;
1350
1351
0
                ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor);
1352
0
                ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture);
1353
0
                ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor);
1354
0
                ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture);
1355
1356
0
                this->materialSpecular = Nullable<MaterialSpecular>(specular);
1357
0
            }
1358
0
        }
1359
1360
        // Extension KHR_texture_transform is handled in ReadTextureProperty
1361
1362
0
        if (r.extensionsUsed.KHR_materials_sheen) {
1363
0
            if (Value *curMaterialSheen = FindObject(*extensions, "KHR_materials_sheen")) {
1364
0
                MaterialSheen sheen;
1365
1366
0
                ReadMember(*curMaterialSheen, "sheenColorFactor", sheen.sheenColorFactor);
1367
0
                ReadTextureProperty(r, *curMaterialSheen, "sheenColorTexture", sheen.sheenColorTexture);
1368
0
                ReadMember(*curMaterialSheen, "sheenRoughnessFactor", sheen.sheenRoughnessFactor);
1369
0
                ReadTextureProperty(r, *curMaterialSheen, "sheenRoughnessTexture", sheen.sheenRoughnessTexture);
1370
1371
0
                this->materialSheen = Nullable<MaterialSheen>(sheen);
1372
0
            }
1373
0
        }
1374
1375
0
        if (r.extensionsUsed.KHR_materials_clearcoat) {
1376
0
            if (Value *curMaterialClearcoat = FindObject(*extensions, "KHR_materials_clearcoat")) {
1377
0
                MaterialClearcoat clearcoat;
1378
1379
0
                ReadMember(*curMaterialClearcoat, "clearcoatFactor", clearcoat.clearcoatFactor);
1380
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatTexture", clearcoat.clearcoatTexture);
1381
0
                ReadMember(*curMaterialClearcoat, "clearcoatRoughnessFactor", clearcoat.clearcoatRoughnessFactor);
1382
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatRoughnessTexture", clearcoat.clearcoatRoughnessTexture);
1383
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatNormalTexture", clearcoat.clearcoatNormalTexture);
1384
1385
0
                this->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
1386
0
            }
1387
0
        }
1388
1389
0
        if (r.extensionsUsed.KHR_materials_transmission) {
1390
0
            if (Value *curMaterialTransmission = FindObject(*extensions, "KHR_materials_transmission")) {
1391
0
                MaterialTransmission transmission;
1392
1393
0
                ReadMember(*curMaterialTransmission, "transmissionFactor", transmission.transmissionFactor);
1394
0
                ReadTextureProperty(r, *curMaterialTransmission, "transmissionTexture", transmission.transmissionTexture);
1395
1396
0
                this->materialTransmission = Nullable<MaterialTransmission>(transmission);
1397
0
            }
1398
0
        }
1399
1400
0
        if (r.extensionsUsed.KHR_materials_volume) {
1401
0
            if (Value *curMaterialVolume = FindObject(*extensions, "KHR_materials_volume")) {
1402
0
                MaterialVolume volume;
1403
1404
0
                ReadMember(*curMaterialVolume, "thicknessFactor", volume.thicknessFactor);
1405
0
                ReadTextureProperty(r, *curMaterialVolume, "thicknessTexture", volume.thicknessTexture);
1406
0
                ReadMember(*curMaterialVolume, "attenuationDistance", volume.attenuationDistance);
1407
0
                ReadMember(*curMaterialVolume, "attenuationColor", volume.attenuationColor);
1408
1409
0
                this->materialVolume = Nullable<MaterialVolume>(volume);
1410
0
            }
1411
0
        }
1412
1413
0
        if (r.extensionsUsed.KHR_materials_ior) {
1414
0
            if (Value *curMaterialIOR = FindObject(*extensions, "KHR_materials_ior")) {
1415
0
                MaterialIOR ior;
1416
1417
0
                ReadMember(*curMaterialIOR, "ior", ior.ior);
1418
1419
0
                this->materialIOR = Nullable<MaterialIOR>(ior);
1420
0
            }
1421
0
        }
1422
1423
0
        if (r.extensionsUsed.KHR_materials_emissive_strength) {
1424
0
            if (Value *curMaterialEmissiveStrength = FindObject(*extensions, "KHR_materials_emissive_strength")) {
1425
0
                MaterialEmissiveStrength emissiveStrength;
1426
1427
0
                ReadMember(*curMaterialEmissiveStrength, "emissiveStrength", emissiveStrength.emissiveStrength);
1428
1429
0
                this->materialEmissiveStrength = Nullable<MaterialEmissiveStrength>(emissiveStrength);
1430
0
            }
1431
0
        }
1432
1433
0
        if (r.extensionsUsed.KHR_materials_anisotropy) {
1434
0
            if (Value *curMaterialAnisotropy = FindObject(*extensions, "KHR_materials_anisotropy")) {
1435
0
                MaterialAnisotropy anisotropy;
1436
1437
0
                ReadMember(*curMaterialAnisotropy, "anisotropyStrength", anisotropy.anisotropyStrength);
1438
0
                ReadMember(*curMaterialAnisotropy, "anisotropyRotation", anisotropy.anisotropyRotation);
1439
0
                ReadTextureProperty(r, *curMaterialAnisotropy, "anisotropyTexture", anisotropy.anisotropyTexture);
1440
1441
0
                this->materialAnisotropy = Nullable<MaterialAnisotropy>(anisotropy);
1442
0
            }
1443
0
        }
1444
1445
0
        unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
1446
0
    }
1447
4.67k
}
1448
1449
13.9k
inline void Material::SetDefaults() {
1450
    //pbr materials
1451
13.9k
    SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
1452
13.9k
    pbrMetallicRoughness.metallicFactor = 1.0f;
1453
13.9k
    pbrMetallicRoughness.roughnessFactor = 1.0f;
1454
1455
13.9k
    SetVector(emissiveFactor, defaultEmissiveFactor);
1456
13.9k
    alphaMode = "OPAQUE";
1457
13.9k
    alphaCutoff = 0.5f;
1458
13.9k
    doubleSided = false;
1459
13.9k
    unlit = false;
1460
13.9k
}
1461
1462
9.26k
inline void PbrSpecularGlossiness::SetDefaults() {
1463
    //pbrSpecularGlossiness properties
1464
9.26k
    SetVector(diffuseFactor, defaultDiffuseFactor);
1465
9.26k
    SetVector(specularFactor, defaultSpecularFactor);
1466
9.26k
    glossinessFactor = 1.0f;
1467
9.26k
}
1468
1469
9.26k
inline void MaterialSpecular::SetDefaults() {
1470
    //KHR_materials_specular properties
1471
9.26k
    SetVector(specularColorFactor, defaultSpecularColorFactor);
1472
9.26k
    specularFactor = 1.f;
1473
9.26k
}
1474
1475
9.26k
inline void MaterialSheen::SetDefaults() {
1476
    //KHR_materials_sheen properties
1477
9.26k
    SetVector(sheenColorFactor, defaultSheenFactor);
1478
9.26k
    sheenRoughnessFactor = 0.f;
1479
9.26k
}
1480
1481
9.26k
inline void MaterialVolume::SetDefaults() {
1482
    //KHR_materials_volume properties
1483
9.26k
    thicknessFactor = 0.f;
1484
9.26k
    attenuationDistance = std::numeric_limits<float>::infinity();
1485
9.26k
    SetVector(attenuationColor, defaultAttenuationColor);
1486
9.26k
}
1487
1488
9.26k
inline void MaterialIOR::SetDefaults() {
1489
    //KHR_materials_ior properties
1490
9.26k
    ior = 1.5f;
1491
9.26k
}
1492
1493
9.26k
inline void MaterialEmissiveStrength::SetDefaults() {
1494
    //KHR_materials_emissive_strength properties
1495
9.26k
    emissiveStrength = 0.f;
1496
9.26k
}
1497
1498
9.26k
inline void MaterialAnisotropy::SetDefaults() {
1499
    //KHR_materials_anisotropy properties
1500
9.26k
    anisotropyStrength = 0.f;
1501
9.26k
    anisotropyRotation = 0.f;
1502
9.26k
}
1503
1504
6.73k
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
1505
6.73k
    Value *curName = FindMember(pJSON_Object, "name");
1506
6.73k
    if (nullptr != curName && curName->IsString()) {
1507
4.79k
        name = curName->GetString();
1508
4.79k
    }
1509
1510
    /****************** Mesh primitives ******************/
1511
6.73k
    Value *curPrimitives = FindArray(pJSON_Object, "primitives");
1512
6.73k
    if (nullptr != curPrimitives) {
1513
6.19k
        this->primitives.resize(curPrimitives->Size());
1514
12.8k
        for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
1515
6.68k
            Value &primitive = (*curPrimitives)[i];
1516
1517
6.68k
            Primitive &prim = this->primitives[i];
1518
6.68k
            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
1519
1520
6.68k
            if (Value *indices = FindUInt(primitive, "indices")) {
1521
4.87k
                prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
1522
4.87k
            }
1523
1524
6.68k
            if (Value *material = FindUInt(primitive, "material")) {
1525
4.77k
                prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
1526
4.77k
            }
1527
1528
6.68k
            if (Value *attrs = FindObject(primitive, "attributes")) {
1529
22.5k
                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
1530
16.8k
                    if (!it->value.IsUint()) continue;
1531
16.8k
                    const char *attr = it->name.GetString();
1532
                    // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
1533
                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
1534
1535
16.8k
                    int undPos = 0;
1536
16.8k
                    Mesh::AccessorList *vec = nullptr;
1537
16.8k
                    if (GetAttribVector(prim, attr, vec, undPos)) {
1538
15.6k
                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1539
15.6k
                        if ((*vec).size() != idx) {
1540
45
                            throw DeadlyImportError("GLTF: Invalid attribute in mesh: ", name, " primitive: ", i, "attrib: ", attr,
1541
45
                                    ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
1542
45
                        }
1543
15.6k
                        (*vec).resize(idx + 1);
1544
15.6k
                        (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
1545
15.6k
                    }
1546
16.8k
                }
1547
5.76k
            }
1548
1549
#ifdef ASSIMP_ENABLE_DRACO
1550
            // KHR_draco_mesh_compression spec: Draco can only be used for glTF Triangles or Triangle Strips
1551
            if (pAsset_Root.extensionsUsed.KHR_draco_mesh_compression && (prim.mode == PrimitiveMode_TRIANGLES || prim.mode == PrimitiveMode_TRIANGLE_STRIP)) {
1552
                // Look for draco mesh compression extension and bufferView
1553
                // Skip if any missing
1554
                if (Value *dracoExt = FindExtension(primitive, "KHR_draco_mesh_compression")) {
1555
                    if (Value *bufView = FindUInt(*dracoExt, "bufferView")) {
1556
                        // Attempt to load indices and attributes using draco compression
1557
                        auto bufferView = pAsset_Root.bufferViews.Retrieve(bufView->GetUint());
1558
                        // Attempt to perform the draco decode on the buffer data
1559
                        const char *bufferViewData = reinterpret_cast<const char *>(bufferView->buffer->GetPointer() + bufferView->byteOffset);
1560
                        draco::DecoderBuffer decoderBuffer;
1561
                        decoderBuffer.Init(bufferViewData, bufferView->byteLength);
1562
                        draco::Decoder decoder;
1563
                        auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
1564
                        if (!decodeResult.ok()) {
1565
                            // A corrupt Draco isn't actually fatal if the primitive data is also provided in a standard buffer, but does anyone do that?
1566
                            throw DeadlyImportError("GLTF: Invalid Draco mesh compression in mesh: ", name, " primitive: ", i, ": ", decodeResult.status().error_msg_string());
1567
                        }
1568
1569
                        // Now we have a draco mesh
1570
                        const std::unique_ptr<draco::Mesh> &pDracoMesh = decodeResult.value();
1571
1572
                        // Redirect the accessors to the decoded data
1573
1574
                        // Indices
1575
                        SetDecodedIndexBuffer_Draco(*pDracoMesh, prim);
1576
1577
                        // Vertex attributes
1578
                        if (Value *attrs = FindObject(*dracoExt, "attributes")) {
1579
                            for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
1580
                                if (!it->value.IsUint()) continue;
1581
                                const char *attr = it->name.GetString();
1582
1583
                                int undPos = 0;
1584
                                Mesh::AccessorList *vec = nullptr;
1585
                                if (GetAttribVector(prim, attr, vec, undPos)) {
1586
                                    size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1587
                                    if (idx >= (*vec).size()) {
1588
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
1589
                                                ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
1590
                                    }
1591
1592
                                    if (!(*vec)[idx]) {
1593
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
1594
                                                ". All draco-encoded attributes must also define an accessor.");
1595
                                    }
1596
1597
                                    Accessor &attribAccessor = *(*vec)[idx];
1598
                                    if (attribAccessor.count == 0)
1599
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr);
1600
1601
                                    // Redirect this accessor to the appropriate Draco vertex attribute data
1602
                                    const uint32_t dracoAttribId = it->value.GetUint();
1603
                                    SetDecodedAttributeBuffer_Draco(*pDracoMesh, dracoAttribId, attribAccessor);
1604
                                }
1605
                            }
1606
                        }
1607
                    }
1608
                }
1609
            }
1610
#endif
1611
1612
6.64k
            Value *targetsArray = FindArray(primitive, "targets");
1613
6.64k
            if (nullptr != targetsArray) {
1614
29
                prim.targets.resize(targetsArray->Size());
1615
87
                for (unsigned int j = 0; j < targetsArray->Size(); ++j) {
1616
58
                    Value &target = (*targetsArray)[j];
1617
58
                    if (!target.IsObject()) {
1618
6
                        continue;
1619
6
                    }
1620
125
                    for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) {
1621
73
                        if (!it->value.IsUint()) {
1622
11
                            continue;
1623
11
                        }
1624
62
                        const char *attr = it->name.GetString();
1625
                        // Valid attribute semantics include POSITION, NORMAL, TANGENT
1626
62
                        int undPos = 0;
1627
62
                        Mesh::AccessorList *vec = nullptr;
1628
62
                        if (GetAttribTargetVector(prim, j, attr, vec, undPos)) {
1629
35
                            size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1630
35
                            if ((*vec).size() <= idx) {
1631
31
                                (*vec).resize(idx + 1);
1632
31
                            }
1633
35
                            (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
1634
35
                        }
1635
62
                    }
1636
52
                }
1637
29
            }
1638
1639
6.64k
            if(this->targetNames.empty())
1640
5.78k
            {
1641
5.78k
                Value *curExtras = FindObject(primitive, "extras");
1642
5.78k
                if (nullptr != curExtras) {
1643
2
                    if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
1644
0
                        this->targetNames.resize(curTargetNames->Size());
1645
0
                        for (unsigned int j = 0; j < curTargetNames->Size(); ++j) {
1646
0
                            Value &targetNameValue = (*curTargetNames)[j];
1647
0
                            if (targetNameValue.IsString()) {
1648
0
                                this->targetNames[j] = targetNameValue.GetString();
1649
0
                            }
1650
0
                        }
1651
0
                    }
1652
2
                }
1653
5.78k
            }
1654
6.64k
        }
1655
6.19k
    }
1656
1657
6.69k
    Value *curWeights = FindArray(pJSON_Object, "weights");
1658
6.69k
    if (nullptr != curWeights) {
1659
40
        this->weights.resize(curWeights->Size());
1660
72
        for (unsigned int i = 0; i < curWeights->Size(); ++i) {
1661
32
            Value &weightValue = (*curWeights)[i];
1662
32
            if (weightValue.IsNumber()) {
1663
21
                this->weights[i] = weightValue.GetFloat();
1664
21
            }
1665
32
        }
1666
40
    }
1667
1668
6.69k
    Value *curExtras = FindObject(pJSON_Object, "extras");
1669
6.69k
    if (nullptr != curExtras) {
1670
1
        if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
1671
0
            this->targetNames.resize(curTargetNames->Size());
1672
0
            for (unsigned int i = 0; i < curTargetNames->Size(); ++i) {
1673
0
                Value &targetNameValue = (*curTargetNames)[i];
1674
0
                if (targetNameValue.IsString()) {
1675
0
                    this->targetNames[i] = targetNameValue.GetString();
1676
0
                }
1677
0
            }
1678
0
        }
1679
1
    }
1680
6.69k
}
1681
1682
111
inline void Camera::Read(Value &obj, Asset & /*r*/) {
1683
111
    std::string type_string = std::string(MemberOrDefault(obj, "type", "perspective"));
1684
111
    if (type_string == "orthographic") {
1685
27
        type = Camera::Orthographic;
1686
84
    } else {
1687
84
        type = Camera::Perspective;
1688
84
    }
1689
1690
111
    const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
1691
1692
111
    Value *it = FindObject(obj, subobjId);
1693
111
    if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
1694
1695
97
    if (type == Camera::Perspective) {
1696
71
        cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
1697
71
        cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f / 2.f);
1698
71
        cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
1699
71
        cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
1700
71
    } else {
1701
26
        cameraProperties.ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
1702
26
        cameraProperties.ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
1703
26
        cameraProperties.ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
1704
26
        cameraProperties.ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
1705
26
    }
1706
97
}
1707
1708
0
inline void Light::Read(Value &obj, Asset & /*r*/) {
1709
#ifndef M_PI
1710
    const float M_PI = 3.14159265358979323846f;
1711
#endif
1712
1713
0
    std::string type_string;
1714
0
    ReadMember(obj, "type", type_string);
1715
0
    if (type_string == "directional")
1716
0
        type = Light::Directional;
1717
0
    else if (type_string == "point")
1718
0
        type = Light::Point;
1719
0
    else
1720
0
        type = Light::Spot;
1721
1722
0
    name = MemberOrDefault(obj, "name", "");
1723
1724
0
    SetVector(color, vec3{ 1.0f, 1.0f, 1.0f });
1725
0
    ReadMember(obj, "color", color);
1726
1727
0
    intensity = MemberOrDefault(obj, "intensity", 1.0f);
1728
1729
0
    ReadMember(obj, "range", range);
1730
1731
0
    if (type == Light::Spot) {
1732
0
        Value *spot = FindObject(obj, "spot");
1733
0
        if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters");
1734
0
        innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f);
1735
0
        outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", static_cast<float>(M_PI / 4.0f));
1736
0
    }
1737
0
}
1738
1739
26.8k
inline void Node::Read(Value &obj, Asset &r) {
1740
26.8k
    if (name.empty()) {
1741
8.95k
        name = id;
1742
8.95k
    }
1743
1744
26.8k
    Value *curChildren = FindArray(obj, "children");
1745
26.8k
    if (nullptr != curChildren) {
1746
11.5k
        this->children.reserve(curChildren->Size());
1747
32.2k
        for (unsigned int i = 0; i < curChildren->Size(); ++i) {
1748
20.7k
            Value &child = (*curChildren)[i];
1749
20.7k
            if (child.IsUint()) {
1750
                // get/create the child node
1751
20.1k
                Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
1752
20.1k
                if (chn) {
1753
19.4k
                    this->children.push_back(chn);
1754
19.4k
                }
1755
20.1k
            }
1756
20.7k
        }
1757
11.5k
    }
1758
1759
26.8k
    Value *curMatrix = FindArray(obj, "matrix");
1760
26.8k
    if (nullptr != curMatrix) {
1761
18.5k
        ReadValue(*curMatrix, this->matrix);
1762
18.5k
    } else {
1763
8.37k
        ReadMember(obj, "translation", translation);
1764
8.37k
        ReadMember(obj, "scale", scale);
1765
8.37k
        ReadMember(obj, "rotation", rotation);
1766
8.37k
    }
1767
1768
26.8k
    Value *curMesh = FindUInt(obj, "mesh");
1769
26.8k
    if (nullptr != curMesh) {
1770
8.62k
        unsigned int numMeshes = 1;
1771
8.62k
        this->meshes.reserve(numMeshes);
1772
8.62k
        Ref<Mesh> meshRef = r.meshes.Retrieve((*curMesh).GetUint());
1773
8.62k
        if (meshRef) {
1774
7.63k
            this->meshes.push_back(meshRef);
1775
7.63k
        }
1776
8.62k
    }
1777
1778
    // Do not retrieve a skin here, just take a reference, to avoid infinite recursion
1779
    // Skins will be properly loaded later
1780
26.8k
    Value *curSkin = FindUInt(obj, "skin");
1781
26.8k
    if (nullptr != curSkin) {
1782
985
        this->skin = r.skins.Get(curSkin->GetUint());
1783
985
    }
1784
1785
26.8k
    Value *curCamera = FindUInt(obj, "camera");
1786
26.8k
    if (nullptr != curCamera) {
1787
133
        this->camera = r.cameras.Retrieve(curCamera->GetUint());
1788
133
        if (this->camera) {
1789
103
            this->camera->id = this->id;
1790
103
        }
1791
133
    }
1792
1793
26.8k
    Value *curExtensions = FindObject(obj, "extensions");
1794
26.8k
    if (nullptr != curExtensions) {
1795
0
        if (r.extensionsUsed.KHR_lights_punctual) {
1796
0
            if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
1797
0
                Value *curLight = FindUInt(*ext, "light");
1798
0
                if (nullptr != curLight) {
1799
0
                    this->light = r.lights.Retrieve(curLight->GetUint());
1800
0
                    if (this->light) {
1801
0
                        this->light->id = this->id;
1802
0
                    }
1803
0
                }
1804
0
            }
1805
0
        }
1806
0
    }
1807
26.8k
}
1808
1809
5.50k
inline void Scene::Read(Value &obj, Asset &r) {
1810
5.50k
    if (Value *scene_name = FindString(obj, "name")) {
1811
200
        if (scene_name->IsString()) {
1812
200
            this->name = scene_name->GetString();
1813
200
        }
1814
200
    }
1815
5.50k
    if (Value *array = FindArray(obj, "nodes")) {
1816
15.0k
        for (unsigned int i = 0; i < array->Size(); ++i) {
1817
9.69k
            if (!(*array)[i].IsUint()) continue;
1818
9.50k
            Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
1819
9.50k
            if (node)
1820
8.30k
                this->nodes.push_back(node);
1821
9.50k
        }
1822
5.37k
    }
1823
5.50k
}
1824
1825
4.80k
inline void Skin::Read(Value &obj, Asset &r) {
1826
4.80k
    if (Value *matrices = FindUInt(obj, "inverseBindMatrices")) {
1827
901
        inverseBindMatrices = r.accessors.Retrieve(matrices->GetUint());
1828
901
    }
1829
1830
4.80k
    if (Value *joints = FindArray(obj, "joints")) {
1831
6.82k
        for (unsigned i = 0; i < joints->Size(); ++i) {
1832
5.97k
            if (!(*joints)[i].IsUint()) continue;
1833
5.85k
            Ref<Node> node = r.nodes.Retrieve((*joints)[i].GetUint());
1834
5.85k
            if (node) {
1835
5.82k
                this->jointNames.push_back(node);
1836
5.82k
            }
1837
5.85k
        }
1838
850
    }
1839
4.80k
}
1840
1841
1.26k
inline void Animation::Read(Value &obj, Asset &r) {
1842
1.26k
    Value *curSamplers = FindArray(obj, "samplers");
1843
1.26k
    if (nullptr != curSamplers) {
1844
491
        for (unsigned i = 0; i < curSamplers->Size(); ++i) {
1845
280
            Value &sampler = (*curSamplers)[i];
1846
1847
280
            Sampler s;
1848
280
            if (Value *input = FindUInt(sampler, "input")) {
1849
201
                s.input = r.accessors.Retrieve(input->GetUint());
1850
201
            }
1851
280
            if (Value *output = FindUInt(sampler, "output")) {
1852
158
                s.output = r.accessors.Retrieve(output->GetUint());
1853
158
            }
1854
280
            s.interpolation = Interpolation_LINEAR;
1855
280
            if (Value *interpolation = FindString(sampler, "interpolation")) {
1856
127
                const std::string interp = interpolation->GetString();
1857
127
                if (interp == "LINEAR") {
1858
107
                    s.interpolation = Interpolation_LINEAR;
1859
107
                } else if (interp == "STEP") {
1860
0
                    s.interpolation = Interpolation_STEP;
1861
20
                } else if (interp == "CUBICSPLINE") {
1862
0
                    s.interpolation = Interpolation_CUBICSPLINE;
1863
0
                }
1864
127
            }
1865
280
            this->samplers.push_back(s);
1866
280
        }
1867
211
    }
1868
1869
1.26k
    Value *curChannels = FindArray(obj, "channels");
1870
1.26k
    if (nullptr != curChannels) {
1871
836
        for (unsigned i = 0; i < curChannels->Size(); ++i) {
1872
562
            Value &channel = (*curChannels)[i];
1873
1874
562
            Channel c;
1875
562
            Value *curSampler = FindUInt(channel, "sampler");
1876
562
            if (nullptr != curSampler) {
1877
186
                c.sampler = curSampler->GetUint();
1878
186
            }
1879
1880
562
            if (Value *target = FindObject(channel, "target")) {
1881
149
                if (Value *node = FindUInt(*target, "node")) {
1882
108
                    c.target.node = r.nodes.Retrieve(node->GetUint());
1883
108
                }
1884
149
                if (Value *path = FindString(*target, "path")) {
1885
132
                    const std::string p = path->GetString();
1886
132
                    if (p == "translation") {
1887
0
                        c.target.path = AnimationPath_TRANSLATION;
1888
132
                    } else if (p == "rotation") {
1889
102
                        c.target.path = AnimationPath_ROTATION;
1890
102
                    } else if (p == "scale") {
1891
0
                        c.target.path = AnimationPath_SCALE;
1892
30
                    } else if (p == "weights") {
1893
6
                        c.target.path = AnimationPath_WEIGHTS;
1894
6
                    }
1895
132
                }
1896
149
            }
1897
562
            this->channels.push_back(c);
1898
562
        }
1899
274
    }
1900
1.26k
}
1901
1902
13.3k
inline void AssetMetadata::Read(Document &doc) {
1903
13.3k
    if (Value *obj = FindObject(doc, "asset")) {
1904
12.6k
        ReadMember(*obj, "copyright", copyright);
1905
12.6k
        ReadMember(*obj, "generator", generator);
1906
1907
12.6k
        if (Value *versionString = FindStringInContext(*obj, "version", "\"asset\"")) {
1908
11.6k
            version = versionString->GetString();
1909
11.6k
        }
1910
12.6k
        Value *curProfile = FindObjectInContext(*obj, "profile", "\"asset\"");
1911
12.6k
        if (nullptr != curProfile) {
1912
66
            ReadMember(*curProfile, "api", this->profile.api);
1913
66
            ReadMember(*curProfile, "version", this->profile.version);
1914
66
        }
1915
12.6k
    }
1916
1917
13.3k
    if (version.empty() || version[0] != '2') {
1918
864
        throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
1919
864
    }
1920
13.3k
}
1921
1922
//
1923
// Asset methods implementation
1924
//
1925
1926
8.29k
inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData) {
1927
8.29k
    ASSIMP_LOG_DEBUG("Reading GLTF2 binary");
1928
8.29k
    GLB_Header header;
1929
8.29k
    if (stream.Read(&header, sizeof(header), 1) != 1) {
1930
4
        throw DeadlyImportError("GLTF: Unable to read the file header");
1931
4
    }
1932
1933
8.28k
    if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
1934
4
        throw DeadlyImportError("GLTF: Invalid binary glTF file");
1935
4
    }
1936
1937
8.28k
    AI_SWAP4(header.version);
1938
8.28k
    asset.version = ai_to_string(header.version);
1939
8.28k
    if (header.version != 2) {
1940
550
        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
1941
550
    }
1942
1943
7.73k
    GLB_Chunk chunk;
1944
7.73k
    if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
1945
2
        throw DeadlyImportError("GLTF: Unable to read JSON chunk");
1946
2
    }
1947
1948
7.73k
    AI_SWAP4(chunk.chunkLength);
1949
7.73k
    AI_SWAP4(chunk.chunkType);
1950
1951
7.73k
    if (chunk.chunkType != ChunkType_JSON) {
1952
104
        throw DeadlyImportError("GLTF: JSON chunk missing");
1953
104
    }
1954
1955
    // read the scene data, ensure null termination
1956
7.62k
    static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
1957
7.62k
    mSceneLength = chunk.chunkLength; // Can't be larger than 4GB (max. uint32_t)
1958
7.62k
    sceneData.resize(mSceneLength + 1);
1959
7.62k
    sceneData[mSceneLength] = '\0';
1960
1961
7.62k
    if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
1962
86
        throw DeadlyImportError("GLTF: Could not read the file contents");
1963
86
    }
1964
1965
7.54k
    uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
1966
7.54k
    if (padding > 0) {
1967
160
        stream.Seek(padding, aiOrigin_CUR);
1968
160
    }
1969
1970
7.54k
    AI_SWAP4(header.length);
1971
7.54k
    mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
1972
7.54k
    if (header.length >= mBodyOffset) {
1973
7.43k
        if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
1974
72
            throw DeadlyImportError("GLTF: Unable to read BIN chunk");
1975
72
        }
1976
1977
7.35k
        AI_SWAP4(chunk.chunkLength);
1978
7.35k
        AI_SWAP4(chunk.chunkType);
1979
1980
7.35k
        if (chunk.chunkType != ChunkType_BIN) {
1981
238
            throw DeadlyImportError("GLTF: BIN chunk missing");
1982
238
        }
1983
1984
7.12k
        mBodyLength = chunk.chunkLength;
1985
7.12k
    } else {
1986
112
        mBodyOffset = mBodyLength = 0;
1987
112
    }
1988
7.54k
}
1989
1990
20.3k
inline rapidjson::Document Asset::ReadDocument(IOStream &stream, bool isBinary, std::vector<char> &sceneData) {
1991
20.3k
    ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
1992
1993
    // is binary? then read the header
1994
20.3k
    if (isBinary) {
1995
8.29k
        SetAsBinary(); // also creates the body buffer
1996
8.29k
        ReadBinaryHeader(stream, sceneData);
1997
12.1k
    } else {
1998
12.1k
        mSceneLength = stream.FileSize();
1999
12.1k
        mBodyLength = 0;
2000
2001
        // Binary format only supports up to 4GB of JSON, use that as a maximum
2002
12.1k
        if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
2003
0
            throw DeadlyImportError("GLTF: JSON size greater than 4GB");
2004
0
        }
2005
2006
        // read the scene data, ensure null termination
2007
12.1k
        sceneData.resize(mSceneLength + 1);
2008
12.1k
        sceneData[mSceneLength] = '\0';
2009
2010
12.1k
        if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
2011
0
            throw DeadlyImportError("GLTF: Could not read the file contents");
2012
0
        }
2013
12.1k
    }
2014
2015
    // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
2016
20.3k
    if (mSceneLength < 2) {
2017
4
        throw DeadlyImportError("GLTF: No JSON file contents");
2018
4
    }
2019
2020
    // parse the JSON document
2021
20.3k
    ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
2022
20.3k
    Document doc;
2023
20.3k
    doc.ParseInsitu(&sceneData[0]);
2024
2025
20.3k
    if (doc.HasParseError()) {
2026
4.31k
        char buffer[32];
2027
4.31k
        ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
2028
4.31k
        throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
2029
4.31k
    }
2030
2031
16.0k
    if (!doc.IsObject()) {
2032
1.58k
        throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
2033
1.58k
    }
2034
2035
14.4k
    return doc;
2036
16.0k
}
2037
2038
inline void Asset::Load(const std::string &pFile, bool isBinary)
2039
6.20k
{
2040
6.20k
    mCurrentAssetDir.clear();
2041
6.20k
    if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
2042
0
        mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
2043
0
    }
2044
2045
6.20k
    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
2046
6.20k
    if (!stream) {
2047
0
        throw DeadlyImportError("GLTF: Could not open file for reading");
2048
0
    }
2049
2050
6.20k
    std::vector<char> sceneData;
2051
6.20k
    rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
2052
2053
    // If a schemaDocumentProvider is available, see if the glTF schema is present.
2054
    // If so, use it to validate the document.
2055
6.20k
    if (mSchemaDocumentProvider) {
2056
0
        if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
2057
            // The schemas are found here: https://github.com/KhronosGroup/glTF/tree/main/specification/2.0/schema
2058
0
            rapidjson::SchemaValidator validator(*gltfSchema);
2059
0
            if (!doc.Accept(validator)) {
2060
0
                rapidjson::StringBuffer pathBuffer;
2061
0
                validator.GetInvalidSchemaPointer().StringifyUriFragment(pathBuffer);
2062
0
                rapidjson::StringBuffer argumentBuffer;
2063
0
                validator.GetInvalidDocumentPointer().StringifyUriFragment(argumentBuffer);
2064
0
                throw DeadlyImportError("GLTF: The JSON document did not satisfy the glTF2 schema. Schema keyword: ", validator.GetInvalidSchemaKeyword(), ", document path: ", pathBuffer.GetString(), ", argument: ", argumentBuffer.GetString());
2065
0
            }
2066
0
        }
2067
0
    }
2068
2069
    // Fill the buffer instance for the current file embedded contents
2070
6.20k
    if (mBodyLength > 0) {
2071
3.53k
        if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
2072
27
            throw DeadlyImportError("GLTF: Unable to read gltf file");
2073
27
        }
2074
3.53k
    }
2075
2076
    // Load the metadata
2077
6.17k
    asset.Read(doc);
2078
6.17k
    ReadExtensionsUsed(doc);
2079
6.17k
    ReadExtensionsRequired(doc);
2080
2081
6.17k
#ifndef ASSIMP_ENABLE_DRACO
2082
    // Is Draco required?
2083
6.17k
    if (extensionsRequired.KHR_draco_mesh_compression) {
2084
1
        throw DeadlyImportError("GLTF: Draco mesh compression not supported.");
2085
1
    }
2086
6.17k
#endif
2087
2088
    // Prepare the dictionaries
2089
90.7k
    for (size_t i = 0; i < mDicts.size(); ++i) {
2090
84.5k
        mDicts[i]->AttachToDocument(doc);
2091
84.5k
    }
2092
2093
    // Read the "extensions" property, then add it to each scene's metadata.
2094
6.17k
    CustomExtension customExtensions;
2095
6.17k
    if (Value *extensionsObject = FindObject(doc, "extensions")) {
2096
0
        customExtensions = glTF2::ReadExtensions("extensions", *extensionsObject);
2097
0
    }
2098
2099
    // Read the "scene" property, which specifies which scene to load
2100
    // and recursively load everything referenced by it
2101
6.17k
    unsigned int sceneIndex = 0;
2102
6.17k
    Value *curScene = FindUInt(doc, "scene");
2103
6.17k
    if (nullptr != curScene) {
2104
4.27k
        sceneIndex = curScene->GetUint();
2105
4.27k
    }
2106
2107
6.17k
    if (Value *scenesArray = FindArray(doc, "scenes")) {
2108
5.56k
        if (sceneIndex < scenesArray->Size()) {
2109
5.51k
            this->scene = scenes.Retrieve(sceneIndex);
2110
2111
5.51k
            this->scene->customExtensions = customExtensions;
2112
5.51k
        }
2113
5.56k
    }
2114
2115
6.17k
    if (Value *skinsArray = FindArray(doc, "skins")) {
2116
5.83k
        for (unsigned int i = 0; i < skinsArray->Size(); ++i) {
2117
4.80k
            skins.Retrieve(i);
2118
4.80k
        }
2119
1.02k
    }
2120
2121
6.17k
    if (Value *animsArray = FindArray(doc, "animations")) {
2122
1.58k
        for (unsigned int i = 0; i < animsArray->Size(); ++i) {
2123
1.27k
            animations.Retrieve(i);
2124
1.27k
        }
2125
310
    }
2126
2127
    // Clean up
2128
70.3k
    for (size_t i = 0; i < mDicts.size(); ++i) {
2129
64.1k
        mDicts[i]->DetachFromDocument();
2130
64.1k
    }
2131
6.17k
}
2132
2133
14.1k
inline bool Asset::CanRead(const std::string &pFile, bool isBinary) {
2134
14.1k
    try {
2135
14.1k
        shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
2136
14.1k
        if (!stream) {
2137
0
            return false;
2138
0
        }
2139
14.1k
        std::vector<char> sceneData;
2140
14.1k
        rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
2141
14.1k
        asset.Read(doc);
2142
14.1k
    } catch (...) {
2143
7.99k
        return false;
2144
7.99k
    }
2145
6.20k
    return true;
2146
14.1k
}
2147
2148
8.29k
inline void Asset::SetAsBinary() {
2149
8.29k
    if (!mBodyBuffer) {
2150
8.29k
        mBodyBuffer = buffers.Create("binary_glTF");
2151
8.29k
        mBodyBuffer->MarkAsSpecial();
2152
8.29k
    }
2153
8.29k
}
2154
2155
// As required extensions are only a concept in glTF 2.0, this is here
2156
// instead of glTFCommon.h
2157
#define CHECK_REQUIRED_EXT(EXT) \
2158
222
    if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
2159
2160
6.06k
inline void Asset::ReadExtensionsRequired(Document &doc) {
2161
6.06k
    Value *extsRequired = FindArray(doc, "extensionsRequired");
2162
6.06k
    if (nullptr == extsRequired) {
2163
5.99k
        return;
2164
5.99k
    }
2165
2166
74
    std::gltf_unordered_map<std::string, bool> exts;
2167
8.89k
    for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
2168
8.81k
        if ((*extsRequired)[i].IsString()) {
2169
8.42k
            exts[(*extsRequired)[i].GetString()] = true;
2170
8.42k
        }
2171
8.81k
    }
2172
2173
74
    CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
2174
74
    CHECK_REQUIRED_EXT(KHR_texture_basisu);
2175
74
    CHECK_REQUIRED_EXT(EXT_texture_webp);
2176
2177
74
#undef CHECK_REQUIRED_EXT
2178
74
}
2179
2180
6.07k
inline void Asset::ReadExtensionsUsed(Document &doc) {
2181
6.07k
    Value *extsUsed = FindArray(doc, "extensionsUsed");
2182
6.07k
    if (!extsUsed) return;
2183
2184
1.04k
    std::gltf_unordered_map<std::string, bool> exts;
2185
2186
55.2k
    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
2187
54.2k
        if ((*extsUsed)[i].IsString()) {
2188
5.21k
            exts[(*extsUsed)[i].GetString()] = true;
2189
5.21k
        }
2190
54.2k
    }
2191
2192
1.04k
    CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
2193
1.04k
    CHECK_EXT(KHR_materials_specular);
2194
1.04k
    CHECK_EXT(KHR_materials_unlit);
2195
1.04k
    CHECK_EXT(KHR_lights_punctual);
2196
1.04k
    CHECK_EXT(KHR_texture_transform);
2197
1.04k
    CHECK_EXT(KHR_materials_sheen);
2198
1.04k
    CHECK_EXT(KHR_materials_clearcoat);
2199
1.04k
    CHECK_EXT(KHR_materials_transmission);
2200
1.04k
    CHECK_EXT(KHR_materials_volume);
2201
1.04k
    CHECK_EXT(KHR_materials_ior);
2202
1.04k
    CHECK_EXT(KHR_materials_emissive_strength);
2203
1.04k
    CHECK_EXT(KHR_materials_anisotropy);
2204
1.04k
    CHECK_EXT(KHR_draco_mesh_compression);
2205
1.04k
    CHECK_EXT(KHR_texture_basisu);
2206
1.04k
    CHECK_EXT(EXT_texture_webp);
2207
2208
1.04k
#undef CHECK_EXT
2209
1.04k
}
2210
2211
20.6k
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool /*absolute*/) {
2212
20.6k
#ifdef ASSIMP_API
2213
20.6k
    return mIOSystem->Open(path, mode);
2214
#else
2215
    if (path.size() < 2) return nullptr;
2216
    if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
2217
        path = mCurrentAssetDir + path;
2218
    }
2219
    FILE *f = fopen(path.c_str(), mode);
2220
    return f ? new IOStream(f) : nullptr;
2221
#endif
2222
20.6k
}
2223
2224
0
inline std::string Asset::FindUniqueID(const std::string &str, const char *suffix) {
2225
0
    std::string id = str;
2226
0
    int n = 1;
2227
0
    if(!id.empty()) {
2228
0
        n = lastUsedID[id];
2229
0
        if(!n) {
2230
0
            lastUsedID[id] = n+1;
2231
0
            return id;
2232
0
        }
2233
0
        id += "_";
2234
0
    }
2235
0
2236
0
    if(suffix) {
2237
0
        id += suffix;
2238
0
        n = lastUsedID[id];
2239
0
        if(!n) {
2240
0
            lastUsedID[id] = n+1;
2241
0
            return id;
2242
0
        }
2243
0
    }
2244
0
2245
0
    lastUsedID[id] = n+1;
2246
0
    return id + "_" + std::to_string(n-1);
2247
0
}
2248
2249
#if _MSC_VER
2250
#   pragma warning(pop)
2251
#endif // _MSC_VER
2252
2253
} // namespace glTF2