Coverage Report

Created: 2026-03-12 06:25

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
50.8k
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
111
50.8k
    CustomExtension ret;
112
50.8k
    ret.name = name;
113
50.8k
    if (obj.IsObject()) {
114
26
        ret.mValues.isPresent = true;
115
130
        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
116
104
            auto &val = it->value;
117
104
            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
118
104
        }
119
50.8k
    } else if (obj.IsArray()) {
120
37
        ret.mValues.value.reserve(obj.Size());
121
37
        ret.mValues.isPresent = true;
122
215
        for (unsigned int i = 0; i < obj.Size(); ++i) {
123
178
            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
124
178
        }
125
50.7k
    } else if (obj.IsNumber()) {
126
25.5k
        if (obj.IsUint64()) {
127
25.4k
            ret.mUint64Value.value = obj.GetUint64();
128
25.4k
            ret.mUint64Value.isPresent = true;
129
25.4k
        } else if (obj.IsInt64()) {
130
17
            ret.mInt64Value.value = obj.GetInt64();
131
17
            ret.mInt64Value.isPresent = true;
132
128
        } else if (obj.IsDouble()) {
133
128
            ret.mDoubleValue.value = obj.GetDouble();
134
128
            ret.mDoubleValue.isPresent = true;
135
128
        }
136
25.5k
    } else if (obj.IsString()) {
137
12.6k
        ReadValue(obj, ret.mStringValue);
138
12.6k
        ret.mStringValue.isPresent = true;
139
12.6k
    } else if (obj.IsBool()) {
140
12.5k
        ret.mBoolValue.value = obj.GetBool();
141
12.5k
        ret.mBoolValue.isPresent = true;
142
12.5k
    }
143
50.8k
    return ret;
144
50.8k
}
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
50.8k
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
111
50.8k
    CustomExtension ret;
112
50.8k
    ret.name = name;
113
50.8k
    if (obj.IsObject()) {
114
26
        ret.mValues.isPresent = true;
115
130
        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
116
104
            auto &val = it->value;
117
104
            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
118
104
        }
119
50.8k
    } else if (obj.IsArray()) {
120
37
        ret.mValues.value.reserve(obj.Size());
121
37
        ret.mValues.isPresent = true;
122
215
        for (unsigned int i = 0; i < obj.Size(); ++i) {
123
178
            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
124
178
        }
125
50.7k
    } else if (obj.IsNumber()) {
126
25.5k
        if (obj.IsUint64()) {
127
25.4k
            ret.mUint64Value.value = obj.GetUint64();
128
25.4k
            ret.mUint64Value.isPresent = true;
129
25.4k
        } else if (obj.IsInt64()) {
130
17
            ret.mInt64Value.value = obj.GetInt64();
131
17
            ret.mInt64Value.isPresent = true;
132
128
        } else if (obj.IsDouble()) {
133
128
            ret.mDoubleValue.value = obj.GetDouble();
134
128
            ret.mDoubleValue.isPresent = true;
135
128
        }
136
25.5k
    } else if (obj.IsString()) {
137
12.6k
        ReadValue(obj, ret.mStringValue);
138
12.6k
        ret.mStringValue.isPresent = true;
139
12.6k
    } else if (obj.IsBool()) {
140
12.5k
        ret.mBoolValue.value = obj.GetBool();
141
12.5k
        ret.mBoolValue.isPresent = true;
142
12.5k
    }
143
50.8k
    return ret;
144
50.8k
}
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::ReadExtensions(char const*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&)
145
146
12.6k
inline Extras ReadExtras(Value &obj) {
147
12.6k
    Extras ret;
148
149
12.6k
    ret.mValues.reserve(obj.MemberCount());
150
63.2k
    for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
151
50.5k
        auto &val = it->value;
152
50.5k
        ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
153
50.5k
    }
154
155
12.6k
    return ret;
156
12.6k
}
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.6k
inline Extras ReadExtras(Value &obj) {
147
12.6k
    Extras ret;
148
149
12.6k
    ret.mValues.reserve(obj.MemberCount());
150
63.2k
    for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
151
50.5k
        auto &val = it->value;
152
50.5k
        ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
153
50.5k
    }
154
155
12.6k
    return ret;
156
12.6k
}
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
22.8k
void SetVector(vec4 &v, const float (&in)[4]) {
177
22.8k
    v[0] = in[0];
178
22.8k
    v[1] = in[1];
179
22.8k
    v[2] = in[2];
180
22.8k
    v[3] = in[3];
181
22.8k
}
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
22.8k
void SetVector(vec4 &v, const float (&in)[4]) {
177
22.8k
    v[0] = in[0];
178
22.8k
    v[1] = in[1];
179
22.8k
    v[2] = in[2];
180
22.8k
    v[3] = in[3];
181
22.8k
}
glTF2Exporter.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [4], float const (&) [4])
Line
Count
Source
176
12
void SetVector(vec4 &v, const float (&in)[4]) {
177
12
    v[0] = in[0];
178
12
    v[1] = in[1];
179
12
    v[2] = in[2];
180
12
    v[3] = in[3];
181
12
}
182
183
50.0k
void SetVector(vec3 &v, const float (&in)[3]) {
184
50.0k
    v[0] = in[0];
185
50.0k
    v[1] = in[1];
186
50.0k
    v[2] = in[2];
187
50.0k
}
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.0k
void SetVector(vec3 &v, const float (&in)[3]) {
184
50.0k
    v[0] = in[0];
185
50.0k
    v[1] = in[1];
186
50.0k
    v[2] = in[2];
187
50.0k
}
glTF2Exporter.cpp:glTF2::(anonymous namespace)::SetVector(float (&) [3], float const (&) [3])
Line
Count
Source
183
30
void SetVector(vec3 &v, const float (&in)[3]) {
184
30
    v[0] = in[0];
185
30
    v[1] = in[1];
186
30
    v[2] = in[2];
187
30
}
188
189
template <int N>
190
56.7k
inline int Compare(const char *attr, const char (&str)[N]) {
191
56.7k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
56.7k
}
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
15.9k
inline int Compare(const char *attr, const char (&str)[N]) {
191
15.9k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
15.9k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<8>(char const*, char const (&) [8])
Line
Count
Source
190
9.32k
inline int Compare(const char *attr, const char (&str)[N]) {
191
9.32k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
9.32k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<6>(char const*, char const (&) [6])
Line
Count
Source
190
5.24k
inline int Compare(const char *attr, const char (&str)[N]) {
191
5.24k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
5.24k
}
glTF2Importer.cpp:int glTF2::(anonymous namespace)::Compare<12>(char const*, char const (&) [12])
Line
Count
Source
190
2.75k
inline int Compare(const char *attr, const char (&str)[N]) {
191
2.75k
    return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
192
2.75k
}
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.9k
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
200
16.9k
    if ((pos = Compare(attr, "POSITION"))) {
201
5.61k
        v = &(p.attributes.position);
202
11.3k
    } else if ((pos = Compare(attr, "NORMAL"))) {
203
4.78k
        v = &(p.attributes.normal);
204
6.53k
    } else if ((pos = Compare(attr, "TANGENT"))) {
205
58
        v = &(p.attributes.tangent);
206
6.48k
    } else if ((pos = Compare(attr, "TEXCOORD"))) {
207
1.23k
        v = &(p.attributes.texcoord);
208
5.24k
    } else if ((pos = Compare(attr, "COLOR"))) {
209
606
        v = &(p.attributes.color);
210
4.63k
    } else if ((pos = Compare(attr, "JOINTS"))) {
211
1.88k
        v = &(p.attributes.joint);
212
2.75k
    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
213
1
        v = &(p.attributes.jointmatrix);
214
2.75k
    } else if ((pos = Compare(attr, "WEIGHTS"))) {
215
1.79k
        v = &(p.attributes.weight);
216
1.79k
    } else
217
954
        return false;
218
15.9k
    return true;
219
16.9k
}
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.9k
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
200
16.9k
    if ((pos = Compare(attr, "POSITION"))) {
201
5.61k
        v = &(p.attributes.position);
202
11.3k
    } else if ((pos = Compare(attr, "NORMAL"))) {
203
4.78k
        v = &(p.attributes.normal);
204
6.53k
    } else if ((pos = Compare(attr, "TANGENT"))) {
205
58
        v = &(p.attributes.tangent);
206
6.48k
    } else if ((pos = Compare(attr, "TEXCOORD"))) {
207
1.23k
        v = &(p.attributes.texcoord);
208
5.24k
    } else if ((pos = Compare(attr, "COLOR"))) {
209
606
        v = &(p.attributes.color);
210
4.63k
    } else if ((pos = Compare(attr, "JOINTS"))) {
211
1.88k
        v = &(p.attributes.joint);
212
2.75k
    } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
213
1
        v = &(p.attributes.jointmatrix);
214
2.75k
    } else if ((pos = Compare(attr, "WEIGHTS"))) {
215
1.79k
        v = &(p.attributes.weight);
216
1.79k
    } else
217
954
        return false;
218
15.9k
    return true;
219
16.9k
}
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
44
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
222
44
    if ((pos = Compare(attr, "POSITION"))) {
223
8
        v = &(p.targets[targetIndex].position);
224
36
    } else if ((pos = Compare(attr, "NORMAL"))) {
225
4
        v = &(p.targets[targetIndex].normal);
226
32
    } else if ((pos = Compare(attr, "TANGENT"))) {
227
8
        v = &(p.targets[targetIndex].tangent);
228
8
    } else
229
24
        return false;
230
20
    return true;
231
44
}
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
44
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
222
44
    if ((pos = Compare(attr, "POSITION"))) {
223
8
        v = &(p.targets[targetIndex].position);
224
36
    } else if ((pos = Compare(attr, "NORMAL"))) {
225
4
        v = &(p.targets[targetIndex].normal);
226
32
    } else if ((pos = Compare(attr, "TANGENT"))) {
227
8
        v = &(p.targets[targetIndex].tangent);
228
8
    } else
229
24
        return false;
230
20
    return true;
231
44
}
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.76k
inline Value *Object::FindString(Value &val, const char *memberId) {
236
7.76k
    return FindStringInContext(val, memberId, id.c_str(), name.c_str());
237
7.76k
}
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
153k
inline Value *Object::FindUInt(Value &val, const char *memberId) {
244
153k
    return FindUIntInContext(val, memberId, id.c_str(), name.c_str());
245
153k
}
246
247
81.7k
inline Value *Object::FindArray(Value &val, const char *memberId) {
248
81.7k
    return FindArrayInContext(val, memberId, id.c_str(), name.c_str());
249
81.7k
}
250
251
236k
inline Value *Object::FindObject(Value &val, const char *memberId) {
252
236k
    return FindObjectInContext(val, memberId, id.c_str(), name.c_str());
253
236k
}
254
255
4
inline Value *Object::FindExtension(Value &val, const char *extensionId) {
256
4
    return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
257
4
}
258
259
81.3k
inline void Object::ReadExtensions(Value &val) {
260
81.3k
    if (Value *curExtensions = FindObject(val, "extensions")) {
261
0
        this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
262
0
    }
263
81.3k
}
264
265
81.3k
inline void Object::ReadExtras(Value &val) {
266
81.3k
    if (Value *curExtras = FindObject(val, "extras")) {
267
12.6k
        this->extras = glTF2::ReadExtras(*curExtras);
268
12.6k
    }
269
81.3k
}
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
224k
        mDictId(dictId),
391
224k
        mExtId(extId),
392
224k
        mDict(nullptr),
393
224k
        mAsset(asset) {
394
224k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
224k
}
glTF2::LazyDict<glTF2::Accessor>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Animation>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Buffer>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::BufferView>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Camera>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Light>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Image>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Material>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Mesh>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Node>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Sampler>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Scene>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Skin>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
glTF2::LazyDict<glTF2::Texture>::LazyDict(glTF2::Asset&, char const*, char const*)
Line
Count
Source
390
16.0k
        mDictId(dictId),
391
16.0k
        mExtId(extId),
392
16.0k
        mDict(nullptr),
393
16.0k
        mAsset(asset) {
394
16.0k
    asset.mDicts.push_back(this); // register to the list of dictionaries
395
16.0k
}
396
397
template <class T>
398
224k
inline LazyDict<T>::~LazyDict() {
399
314k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
89.3k
        delete mObjs[i];
401
89.3k
    }
402
224k
}
glTF2::LazyDict<glTF2::Texture>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.3k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
255
        delete mObjs[i];
401
255
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Skin>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
19.9k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
3.87k
        delete mObjs[i];
401
3.87k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Scene>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
20.2k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
4.16k
        delete mObjs[i];
401
4.16k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Sampler>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.2k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
224
        delete mObjs[i];
401
224
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Node>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
41.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
25.4k
        delete mObjs[i];
401
25.4k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Mesh>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
21.7k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
5.63k
        delete mObjs[i];
401
5.63k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Material>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
20.8k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
4.74k
        delete mObjs[i];
401
4.74k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Image>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.3k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
242
        delete mObjs[i];
401
242
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Light>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.0k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
0
        delete mObjs[i];
401
0
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Camera>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.1k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
99
        delete mObjs[i];
401
99
    }
402
16.0k
}
glTF2::LazyDict<glTF2::BufferView>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
30.8k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
14.7k
        delete mObjs[i];
401
14.7k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Buffer>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
25.1k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
9.12k
        delete mObjs[i];
401
9.12k
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Animation>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
16.3k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
249
        delete mObjs[i];
401
249
    }
402
16.0k
}
glTF2::LazyDict<glTF2::Accessor>::~LazyDict()
Line
Count
Source
398
16.0k
inline LazyDict<T>::~LazyDict() {
399
36.5k
    for (size_t i = 0; i < mObjs.size(); ++i) {
400
20.4k
        delete mObjs[i];
401
20.4k
    }
402
16.0k
}
403
404
template <class T>
405
80.3k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
80.3k
    Value *container = nullptr;
407
80.3k
    const char *context = nullptr;
408
409
80.3k
    if (mExtId) {
410
5.74k
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
74.6k
    } else {
415
74.6k
        container = &doc;
416
74.6k
        context = "the document";
417
74.6k
    }
418
419
80.3k
    if (container) {
420
74.6k
        mDict = FindArrayInContext(*container, mDictId, context);
421
74.6k
    }
422
80.3k
}
glTF2::LazyDict<glTF2::Accessor>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.75k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.75k
    Value *container = nullptr;
407
5.75k
    const char *context = nullptr;
408
409
5.75k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.75k
    } else {
415
5.75k
        container = &doc;
416
5.75k
        context = "the document";
417
5.75k
    }
418
419
5.75k
    if (container) {
420
5.75k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.75k
    }
422
5.75k
}
glTF2::LazyDict<glTF2::Animation>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Buffer>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::BufferView>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Camera>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Light>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
5.74k
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
0
        container = &doc;
416
0
        context = "the document";
417
0
    }
418
419
5.74k
    if (container) {
420
0
        mDict = FindArrayInContext(*container, mDictId, context);
421
0
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Image>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Material>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.74k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.74k
    Value *container = nullptr;
407
5.74k
    const char *context = nullptr;
408
409
5.74k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.74k
    } else {
415
5.74k
        container = &doc;
416
5.74k
        context = "the document";
417
5.74k
    }
418
419
5.74k
    if (container) {
420
5.74k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.74k
    }
422
5.74k
}
glTF2::LazyDict<glTF2::Mesh>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.73k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.73k
    Value *container = nullptr;
407
5.73k
    const char *context = nullptr;
408
409
5.73k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.73k
    } else {
415
5.73k
        container = &doc;
416
5.73k
        context = "the document";
417
5.73k
    }
418
419
5.73k
    if (container) {
420
5.73k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.73k
    }
422
5.73k
}
glTF2::LazyDict<glTF2::Node>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.73k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.73k
    Value *container = nullptr;
407
5.73k
    const char *context = nullptr;
408
409
5.73k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.73k
    } else {
415
5.73k
        container = &doc;
416
5.73k
        context = "the document";
417
5.73k
    }
418
419
5.73k
    if (container) {
420
5.73k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.73k
    }
422
5.73k
}
glTF2::LazyDict<glTF2::Sampler>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.73k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.73k
    Value *container = nullptr;
407
5.73k
    const char *context = nullptr;
408
409
5.73k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.73k
    } else {
415
5.73k
        container = &doc;
416
5.73k
        context = "the document";
417
5.73k
    }
418
419
5.73k
    if (container) {
420
5.73k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.73k
    }
422
5.73k
}
glTF2::LazyDict<glTF2::Scene>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.73k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.73k
    Value *container = nullptr;
407
5.73k
    const char *context = nullptr;
408
409
5.73k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.73k
    } else {
415
5.73k
        container = &doc;
416
5.73k
        context = "the document";
417
5.73k
    }
418
419
5.73k
    if (container) {
420
5.73k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.73k
    }
422
5.73k
}
glTF2::LazyDict<glTF2::Skin>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.72k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.72k
    Value *container = nullptr;
407
5.72k
    const char *context = nullptr;
408
409
5.72k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.72k
    } else {
415
5.72k
        container = &doc;
416
5.72k
        context = "the document";
417
5.72k
    }
418
419
5.72k
    if (container) {
420
5.72k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.72k
    }
422
5.72k
}
glTF2::LazyDict<glTF2::Texture>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&)
Line
Count
Source
405
5.72k
inline void LazyDict<T>::AttachToDocument(Document &doc) {
406
5.72k
    Value *container = nullptr;
407
5.72k
    const char *context = nullptr;
408
409
5.72k
    if (mExtId) {
410
0
        if (Value *exts = FindObject(doc, "extensions")) {
411
0
            container = FindObjectInContext(*exts, mExtId, "extensions");
412
0
            context = mExtId;
413
0
        }
414
5.72k
    } else {
415
5.72k
        container = &doc;
416
5.72k
        context = "the document";
417
5.72k
    }
418
419
5.72k
    if (container) {
420
5.72k
        mDict = FindArrayInContext(*container, mDictId, context);
421
5.72k
    }
422
5.72k
}
423
424
template <class T>
425
59.4k
inline void LazyDict<T>::DetachFromDocument() {
426
59.4k
    mDict = nullptr;
427
59.4k
}
glTF2::LazyDict<glTF2::Accessor>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Animation>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Buffer>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::BufferView>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Camera>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Light>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Image>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Material>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Mesh>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Node>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Sampler>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Scene>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Skin>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
glTF2::LazyDict<glTF2::Texture>::DetachFromDocument()
Line
Count
Source
425
4.24k
inline void LazyDict<T>::DetachFromDocument() {
426
4.24k
    mDict = nullptr;
427
4.24k
}
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
112k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
112k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
112k
    if (it != mObjsByOIndex.end()) { // already created?
476
23.8k
        return Ref<T>(mObjs, it->second);
477
23.8k
    }
478
479
    // read it from the JSON object
480
88.1k
    if (!mDict) {
481
142
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
142
    }
483
484
88.0k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
88.0k
    if (i >= mDict->Size()) {
489
392
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
392
    }
491
492
87.6k
    Value &obj = (*mDict)[i];
493
494
87.6k
    if (!obj.IsObject()) {
495
31
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
31
    }
497
498
87.6k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
35
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
35
    }
501
87.5k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
87.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
87.5k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
87.5k
    inst->oIndex = i;
508
87.5k
    ReadMember(obj, "name", inst->name);
509
87.5k
    inst->Read(obj, mAsset);
510
87.5k
    inst->ReadExtensions(obj);
511
87.5k
    inst->ReadExtras(obj);
512
513
87.5k
    Ref<T> result = Add(inst.release());
514
87.5k
    mRecursiveReferenceCheck.erase(i);
515
87.5k
    return result;
516
87.6k
}
glTF2::LazyDict<glTF2::Buffer>::Retrieve(unsigned int)
Line
Count
Source
473
15.3k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
15.3k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
15.3k
    if (it != mObjsByOIndex.end()) { // already created?
476
13.7k
        return Ref<T>(mObjs, it->second);
477
13.7k
    }
478
479
    // read it from the JSON object
480
1.59k
    if (!mDict) {
481
5
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
5
    }
483
484
1.59k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
1.59k
    if (i >= mDict->Size()) {
489
28
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
28
    }
491
492
1.56k
    Value &obj = (*mDict)[i];
493
494
1.56k
    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.56k
    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.56k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
1.56k
    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.56k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
1.56k
    inst->oIndex = i;
508
1.56k
    ReadMember(obj, "name", inst->name);
509
1.56k
    inst->Read(obj, mAsset);
510
1.56k
    inst->ReadExtensions(obj);
511
1.56k
    inst->ReadExtras(obj);
512
513
1.56k
    Ref<T> result = Add(inst.release());
514
1.56k
    mRecursiveReferenceCheck.erase(i);
515
1.56k
    return result;
516
1.56k
}
glTF2::LazyDict<glTF2::BufferView>::Retrieve(unsigned int)
Line
Count
Source
473
16.3k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
16.3k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
16.3k
    if (it != mObjsByOIndex.end()) { // already created?
476
998
        return Ref<T>(mObjs, it->second);
477
998
    }
478
479
    // read it from the JSON object
480
15.3k
    if (!mDict) {
481
15
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
15
    }
483
484
15.3k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
15.3k
    if (i >= mDict->Size()) {
489
44
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
44
    }
491
492
15.3k
    Value &obj = (*mDict)[i];
493
494
15.3k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
15.3k
    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
15.3k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
15.3k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
15.3k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
15.3k
    inst->oIndex = i;
508
15.3k
    ReadMember(obj, "name", inst->name);
509
15.3k
    inst->Read(obj, mAsset);
510
15.3k
    inst->ReadExtensions(obj);
511
15.3k
    inst->ReadExtras(obj);
512
513
15.3k
    Ref<T> result = Add(inst.release());
514
15.3k
    mRecursiveReferenceCheck.erase(i);
515
15.3k
    return result;
516
15.3k
}
glTF2::LazyDict<glTF2::Image>::Retrieve(unsigned int)
Line
Count
Source
473
268
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
268
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
268
    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
268
    if (!mDict) {
481
3
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
3
    }
483
484
265
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
265
    if (i >= mDict->Size()) {
489
6
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
6
    }
491
492
259
    Value &obj = (*mDict)[i];
493
494
259
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
258
    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
258
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
258
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
258
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
258
    inst->oIndex = i;
508
258
    ReadMember(obj, "name", inst->name);
509
258
    inst->Read(obj, mAsset);
510
258
    inst->ReadExtensions(obj);
511
258
    inst->ReadExtras(obj);
512
513
258
    Ref<T> result = Add(inst.release());
514
258
    mRecursiveReferenceCheck.erase(i);
515
258
    return result;
516
258
}
glTF2::LazyDict<glTF2::Sampler>::Retrieve(unsigned int)
Line
Count
Source
473
238
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
238
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
238
    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
238
    if (!mDict) {
481
8
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
8
    }
483
484
230
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
230
    if (i >= mDict->Size()) {
489
5
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
5
    }
491
492
225
    Value &obj = (*mDict)[i];
493
494
225
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
224
    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
224
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
224
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
224
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
224
    inst->oIndex = i;
508
224
    ReadMember(obj, "name", inst->name);
509
224
    inst->Read(obj, mAsset);
510
224
    inst->ReadExtensions(obj);
511
224
    inst->ReadExtras(obj);
512
513
224
    Ref<T> result = Add(inst.release());
514
224
    mRecursiveReferenceCheck.erase(i);
515
224
    return result;
516
224
}
glTF2::LazyDict<glTF2::Texture>::Retrieve(unsigned int)
Line
Count
Source
473
400
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
400
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
400
    if (it != mObjsByOIndex.end()) { // already created?
476
88
        return Ref<T>(mObjs, it->second);
477
88
    }
478
479
    // read it from the JSON object
480
312
    if (!mDict) {
481
4
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
4
    }
483
484
308
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
308
    if (i >= mDict->Size()) {
489
8
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
8
    }
491
492
300
    Value &obj = (*mDict)[i];
493
494
300
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
299
    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
299
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
299
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
299
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
299
    inst->oIndex = i;
508
299
    ReadMember(obj, "name", inst->name);
509
299
    inst->Read(obj, mAsset);
510
299
    inst->ReadExtensions(obj);
511
299
    inst->ReadExtras(obj);
512
513
299
    Ref<T> result = Add(inst.release());
514
299
    mRecursiveReferenceCheck.erase(i);
515
299
    return result;
516
299
}
glTF2::LazyDict<glTF2::Accessor>::Retrieve(unsigned int)
Line
Count
Source
473
22.2k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
22.2k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
22.2k
    if (it != mObjsByOIndex.end()) { // already created?
476
845
        return Ref<T>(mObjs, it->second);
477
845
    }
478
479
    // read it from the JSON object
480
21.4k
    if (!mDict) {
481
26
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
26
    }
483
484
21.3k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
21.3k
    if (i >= mDict->Size()) {
489
105
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
105
    }
491
492
21.2k
    Value &obj = (*mDict)[i];
493
494
21.2k
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
21.2k
    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
21.2k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
21.2k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
21.2k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
21.2k
    inst->oIndex = i;
508
21.2k
    ReadMember(obj, "name", inst->name);
509
21.2k
    inst->Read(obj, mAsset);
510
21.2k
    inst->ReadExtensions(obj);
511
21.2k
    inst->ReadExtras(obj);
512
513
21.2k
    Ref<T> result = Add(inst.release());
514
21.2k
    mRecursiveReferenceCheck.erase(i);
515
21.2k
    return result;
516
21.2k
}
glTF2::LazyDict<glTF2::Material>::Retrieve(unsigned int)
Line
Count
Source
473
4.88k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
4.88k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
4.88k
    if (it != mObjsByOIndex.end()) { // already created?
476
62
        return Ref<T>(mObjs, it->second);
477
62
    }
478
479
    // read it from the JSON object
480
4.82k
    if (!mDict) {
481
5
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
5
    }
483
484
4.82k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
4.82k
    if (i >= mDict->Size()) {
489
14
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
14
    }
491
492
4.80k
    Value &obj = (*mDict)[i];
493
494
4.80k
    if (!obj.IsObject()) {
495
2
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
2
    }
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::Node>::Retrieve(unsigned int)
Line
Count
Source
473
33.8k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
33.8k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
33.8k
    if (it != mObjsByOIndex.end()) { // already created?
476
6.25k
        return Ref<T>(mObjs, it->second);
477
6.25k
    }
478
479
    // read it from the JSON object
480
27.6k
    if (!mDict) {
481
38
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
38
    }
483
484
27.5k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
27.5k
    if (i >= mDict->Size()) {
489
129
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
129
    }
491
492
27.4k
    Value &obj = (*mDict)[i];
493
494
27.4k
    if (!obj.IsObject()) {
495
5
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
5
    }
497
498
27.4k
    if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
499
35
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
500
35
    }
501
27.4k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
27.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
27.4k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
27.4k
    inst->oIndex = i;
508
27.4k
    ReadMember(obj, "name", inst->name);
509
27.4k
    inst->Read(obj, mAsset);
510
27.4k
    inst->ReadExtensions(obj);
511
27.4k
    inst->ReadExtras(obj);
512
513
27.4k
    Ref<T> result = Add(inst.release());
514
27.4k
    mRecursiveReferenceCheck.erase(i);
515
27.4k
    return result;
516
27.4k
}
glTF2::LazyDict<glTF2::Mesh>::Retrieve(unsigned int)
Line
Count
Source
473
8.56k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
8.56k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
8.56k
    if (it != mObjsByOIndex.end()) { // already created?
476
1.87k
        return Ref<T>(mObjs, it->second);
477
1.87k
    }
478
479
    // read it from the JSON object
480
6.68k
    if (!mDict) {
481
35
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
35
    }
483
484
6.65k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
6.65k
    if (i >= mDict->Size()) {
489
41
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
41
    }
491
492
6.61k
    Value &obj = (*mDict)[i];
493
494
6.61k
    if (!obj.IsObject()) {
495
6
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
6
    }
497
498
6.60k
    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.60k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
6.60k
    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.60k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
6.60k
    inst->oIndex = i;
508
6.60k
    ReadMember(obj, "name", inst->name);
509
6.60k
    inst->Read(obj, mAsset);
510
6.60k
    inst->ReadExtensions(obj);
511
6.60k
    inst->ReadExtras(obj);
512
513
6.60k
    Ref<T> result = Add(inst.release());
514
6.60k
    mRecursiveReferenceCheck.erase(i);
515
6.60k
    return result;
516
6.60k
}
glTF2::LazyDict<glTF2::Camera>::Retrieve(unsigned int)
Line
Count
Source
473
130
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
130
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
130
    if (it != mObjsByOIndex.end()) { // already created?
476
4
        return Ref<T>(mObjs, it->second);
477
4
    }
478
479
    // read it from the JSON object
480
126
    if (!mDict) {
481
3
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
3
    }
483
484
123
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
123
    if (i >= mDict->Size()) {
489
12
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
12
    }
491
492
111
    Value &obj = (*mDict)[i];
493
494
111
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
110
    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
110
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
110
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
110
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
110
    inst->oIndex = i;
508
110
    ReadMember(obj, "name", inst->name);
509
110
    inst->Read(obj, mAsset);
510
110
    inst->ReadExtensions(obj);
511
110
    inst->ReadExtras(obj);
512
513
110
    Ref<T> result = Add(inst.release());
514
110
    mRecursiveReferenceCheck.erase(i);
515
110
    return result;
516
110
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Light>::Retrieve(unsigned int)
glTF2::LazyDict<glTF2::Scene>::Retrieve(unsigned int)
Line
Count
Source
473
5.45k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
5.45k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
5.45k
    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.45k
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
5.45k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
5.45k
    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.45k
    Value &obj = (*mDict)[i];
493
494
5.45k
    if (!obj.IsObject()) {
495
8
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
8
    }
497
498
5.44k
    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.44k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
5.44k
    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.44k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
5.44k
    inst->oIndex = i;
508
5.44k
    ReadMember(obj, "name", inst->name);
509
5.44k
    inst->Read(obj, mAsset);
510
5.44k
    inst->ReadExtensions(obj);
511
5.44k
    inst->ReadExtras(obj);
512
513
5.44k
    Ref<T> result = Add(inst.release());
514
5.44k
    mRecursiveReferenceCheck.erase(i);
515
5.44k
    return result;
516
5.44k
}
glTF2::LazyDict<glTF2::Skin>::Retrieve(unsigned int)
Line
Count
Source
473
3.96k
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
3.96k
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
3.96k
    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
3.96k
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
3.96k
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
3.96k
    if (i >= mDict->Size()) {
489
0
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
0
    }
491
492
3.96k
    Value &obj = (*mDict)[i];
493
494
3.96k
    if (!obj.IsObject()) {
495
2
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
2
    }
497
498
3.96k
    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
3.96k
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
3.96k
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
3.96k
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
3.96k
    inst->oIndex = i;
508
3.96k
    ReadMember(obj, "name", inst->name);
509
3.96k
    inst->Read(obj, mAsset);
510
3.96k
    inst->ReadExtensions(obj);
511
3.96k
    inst->ReadExtras(obj);
512
513
3.96k
    Ref<T> result = Add(inst.release());
514
3.96k
    mRecursiveReferenceCheck.erase(i);
515
3.96k
    return result;
516
3.96k
}
glTF2::LazyDict<glTF2::Animation>::Retrieve(unsigned int)
Line
Count
Source
473
326
Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
474
326
    typename Dict::iterator it = mObjsByOIndex.find(i);
475
326
    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
326
    if (!mDict) {
481
0
        throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
482
0
    }
483
484
326
    if (!mDict->IsArray()) {
485
0
        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
486
0
    }
487
488
326
    if (i >= mDict->Size()) {
489
0
        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
490
0
    }
491
492
326
    Value &obj = (*mDict)[i];
493
494
326
    if (!obj.IsObject()) {
495
1
        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
496
1
    }
497
498
325
    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
325
    mRecursiveReferenceCheck.insert(i);
502
503
    // Unique ptr prevents memory leak in case of Read throws an exception
504
325
    auto inst = std::unique_ptr<T>(new T());
505
    // Try to make this human readable so it can be used in error messages.
506
325
    inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
507
325
    inst->oIndex = i;
508
325
    ReadMember(obj, "name", inst->name);
509
325
    inst->Read(obj, mAsset);
510
325
    inst->ReadExtensions(obj);
511
325
    inst->ReadExtras(obj);
512
513
325
    Ref<T> result = Add(inst.release());
514
325
    mRecursiveReferenceCheck.erase(i);
515
325
    return result;
516
325
}
517
518
template <class T>
519
967
Ref<T> LazyDict<T>::Get(unsigned int i) {
520
967
    return Ref<T>(mObjs, i);
521
967
}
glTF2::LazyDict<glTF2::Skin>::Get(unsigned int)
Line
Count
Source
519
967
Ref<T> LazyDict<T>::Get(unsigned int i) {
520
967
    return Ref<T>(mObjs, i);
521
967
}
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.3k
Ref<T> LazyDict<T>::Add(T *obj) {
537
89.3k
    unsigned int idx = unsigned(mObjs.size());
538
89.3k
    mObjs.push_back(obj);
539
89.3k
    mObjsByOIndex[obj->oIndex] = idx;
540
89.3k
    mObjsById[obj->id] = idx;
541
89.3k
    return Ref<T>(mObjs, idx);
542
89.3k
}
glTF2::LazyDict<glTF2::Buffer>::Add(glTF2::Buffer*)
Line
Count
Source
536
9.12k
Ref<T> LazyDict<T>::Add(T *obj) {
537
9.12k
    unsigned int idx = unsigned(mObjs.size());
538
9.12k
    mObjs.push_back(obj);
539
9.12k
    mObjsByOIndex[obj->oIndex] = idx;
540
9.12k
    mObjsById[obj->id] = idx;
541
9.12k
    return Ref<T>(mObjs, idx);
542
9.12k
}
glTF2::LazyDict<glTF2::BufferView>::Add(glTF2::BufferView*)
Line
Count
Source
536
14.7k
Ref<T> LazyDict<T>::Add(T *obj) {
537
14.7k
    unsigned int idx = unsigned(mObjs.size());
538
14.7k
    mObjs.push_back(obj);
539
14.7k
    mObjsByOIndex[obj->oIndex] = idx;
540
14.7k
    mObjsById[obj->id] = idx;
541
14.7k
    return Ref<T>(mObjs, idx);
542
14.7k
}
glTF2::LazyDict<glTF2::Image>::Add(glTF2::Image*)
Line
Count
Source
536
242
Ref<T> LazyDict<T>::Add(T *obj) {
537
242
    unsigned int idx = unsigned(mObjs.size());
538
242
    mObjs.push_back(obj);
539
242
    mObjsByOIndex[obj->oIndex] = idx;
540
242
    mObjsById[obj->id] = idx;
541
242
    return Ref<T>(mObjs, idx);
542
242
}
glTF2::LazyDict<glTF2::Sampler>::Add(glTF2::Sampler*)
Line
Count
Source
536
224
Ref<T> LazyDict<T>::Add(T *obj) {
537
224
    unsigned int idx = unsigned(mObjs.size());
538
224
    mObjs.push_back(obj);
539
224
    mObjsByOIndex[obj->oIndex] = idx;
540
224
    mObjsById[obj->id] = idx;
541
224
    return Ref<T>(mObjs, idx);
542
224
}
glTF2::LazyDict<glTF2::Texture>::Add(glTF2::Texture*)
Line
Count
Source
536
255
Ref<T> LazyDict<T>::Add(T *obj) {
537
255
    unsigned int idx = unsigned(mObjs.size());
538
255
    mObjs.push_back(obj);
539
255
    mObjsByOIndex[obj->oIndex] = idx;
540
255
    mObjsById[obj->id] = idx;
541
255
    return Ref<T>(mObjs, idx);
542
255
}
glTF2::LazyDict<glTF2::Accessor>::Add(glTF2::Accessor*)
Line
Count
Source
536
20.4k
Ref<T> LazyDict<T>::Add(T *obj) {
537
20.4k
    unsigned int idx = unsigned(mObjs.size());
538
20.4k
    mObjs.push_back(obj);
539
20.4k
    mObjsByOIndex[obj->oIndex] = idx;
540
20.4k
    mObjsById[obj->id] = idx;
541
20.4k
    return Ref<T>(mObjs, idx);
542
20.4k
}
glTF2::LazyDict<glTF2::Material>::Add(glTF2::Material*)
Line
Count
Source
536
4.74k
Ref<T> LazyDict<T>::Add(T *obj) {
537
4.74k
    unsigned int idx = unsigned(mObjs.size());
538
4.74k
    mObjs.push_back(obj);
539
4.74k
    mObjsByOIndex[obj->oIndex] = idx;
540
4.74k
    mObjsById[obj->id] = idx;
541
4.74k
    return Ref<T>(mObjs, idx);
542
4.74k
}
glTF2::LazyDict<glTF2::Node>::Add(glTF2::Node*)
Line
Count
Source
536
25.4k
Ref<T> LazyDict<T>::Add(T *obj) {
537
25.4k
    unsigned int idx = unsigned(mObjs.size());
538
25.4k
    mObjs.push_back(obj);
539
25.4k
    mObjsByOIndex[obj->oIndex] = idx;
540
25.4k
    mObjsById[obj->id] = idx;
541
25.4k
    return Ref<T>(mObjs, idx);
542
25.4k
}
glTF2::LazyDict<glTF2::Mesh>::Add(glTF2::Mesh*)
Line
Count
Source
536
5.63k
Ref<T> LazyDict<T>::Add(T *obj) {
537
5.63k
    unsigned int idx = unsigned(mObjs.size());
538
5.63k
    mObjs.push_back(obj);
539
5.63k
    mObjsByOIndex[obj->oIndex] = idx;
540
5.63k
    mObjsById[obj->id] = idx;
541
5.63k
    return Ref<T>(mObjs, idx);
542
5.63k
}
glTF2::LazyDict<glTF2::Camera>::Add(glTF2::Camera*)
Line
Count
Source
536
99
Ref<T> LazyDict<T>::Add(T *obj) {
537
99
    unsigned int idx = unsigned(mObjs.size());
538
99
    mObjs.push_back(obj);
539
99
    mObjsByOIndex[obj->oIndex] = idx;
540
99
    mObjsById[obj->id] = idx;
541
99
    return Ref<T>(mObjs, idx);
542
99
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::Light>::Add(glTF2::Light*)
glTF2::LazyDict<glTF2::Scene>::Add(glTF2::Scene*)
Line
Count
Source
536
4.16k
Ref<T> LazyDict<T>::Add(T *obj) {
537
4.16k
    unsigned int idx = unsigned(mObjs.size());
538
4.16k
    mObjs.push_back(obj);
539
4.16k
    mObjsByOIndex[obj->oIndex] = idx;
540
4.16k
    mObjsById[obj->id] = idx;
541
4.16k
    return Ref<T>(mObjs, idx);
542
4.16k
}
glTF2::LazyDict<glTF2::Skin>::Add(glTF2::Skin*)
Line
Count
Source
536
3.87k
Ref<T> LazyDict<T>::Add(T *obj) {
537
3.87k
    unsigned int idx = unsigned(mObjs.size());
538
3.87k
    mObjs.push_back(obj);
539
3.87k
    mObjsByOIndex[obj->oIndex] = idx;
540
3.87k
    mObjsById[obj->id] = idx;
541
3.87k
    return Ref<T>(mObjs, idx);
542
3.87k
}
glTF2::LazyDict<glTF2::Animation>::Add(glTF2::Animation*)
Line
Count
Source
536
249
Ref<T> LazyDict<T>::Add(T *obj) {
537
249
    unsigned int idx = unsigned(mObjs.size());
538
249
    mObjs.push_back(obj);
539
249
    mObjsByOIndex[obj->oIndex] = idx;
540
249
    mObjsById[obj->id] = idx;
541
249
    return Ref<T>(mObjs, idx);
542
249
}
543
544
template <class T>
545
7.98k
Ref<T> LazyDict<T>::Create(const char *id) {
546
7.98k
    T *inst = new T();
547
7.98k
    unsigned int idx = unsigned(mObjs.size());
548
7.98k
    inst->id = id;
549
7.98k
    inst->index = idx;
550
7.98k
    inst->oIndex = idx;
551
7.98k
    return Add(inst);
552
7.98k
}
Unexecuted instantiation: glTF2::LazyDict<glTF2::BufferView>::Create(char const*)
glTF2::LazyDict<glTF2::Buffer>::Create(char const*)
Line
Count
Source
545
7.98k
Ref<T> LazyDict<T>::Create(const char *id) {
546
7.98k
    T *inst = new T();
547
7.98k
    unsigned int idx = unsigned(mObjs.size());
548
7.98k
    inst->id = id;
549
7.98k
    inst->index = idx;
550
7.98k
    inst->oIndex = idx;
551
7.98k
    return Add(inst);
552
7.98k
}
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.54k
        byteLength(0),
559
9.54k
        type(Type_arraybuffer),
560
9.54k
        EncodedRegion_Current(nullptr),
561
9.54k
        mIsSpecial(false) {
562
    // empty
563
9.54k
}
564
565
9.54k
inline Buffer::~Buffer() {
566
9.54k
    for (SEncodedRegion *reg : EncodedRegion_List) delete reg;
567
9.54k
}
568
569
0
inline const char *Buffer::TranslateId(Asset & /*r*/, const char *id) {
570
0
    return id;
571
0
}
572
573
1.56k
inline void Buffer::Read(Value &obj, Asset &r) {
574
1.56k
    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
575
1.56k
    byteLength = statedLength;
576
577
1.56k
    Value *it = FindString(obj, "uri");
578
1.56k
    if (!it) {
579
25
        if (statedLength > 0) {
580
18
            throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
581
18
        }
582
7
        return;
583
25
    }
584
585
1.53k
    const char *uri = it->GetString();
586
587
1.53k
    glTFCommon::Util::DataURI dataURI;
588
1.53k
    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
589
1.23k
        if (dataURI.base64) {
590
1.18k
            uint8_t *data = nullptr;
591
1.18k
            this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data);
592
1.18k
            this->mData.reset(data, std::default_delete<uint8_t[]>());
593
594
1.18k
            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.18k
        } else { // assume raw data
599
49
            if (statedLength != dataURI.dataLength) {
600
47
                throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
601
47
                        " bytes, but found ", ai_to_string(dataURI.dataLength));
602
47
            }
603
604
2
            this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
605
2
            memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
606
2
        }
607
1.23k
    } else { // Local file
608
302
        if (byteLength > 0) {
609
285
            std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir.back() == '/' ? r.mCurrentAssetDir : r.mCurrentAssetDir + '/') : "";
610
611
285
            IOStream *file = r.OpenFile(dir + uri, "rb");
612
285
            if (file) {
613
23
                bool ok = LoadFromStream(*file, byteLength);
614
23
                delete file;
615
616
23
                if (!ok)
617
0
                    throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
618
262
            } else {
619
262
                throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
620
262
            }
621
285
        }
622
302
    }
623
1.53k
}
624
625
3.57k
inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
626
3.57k
    byteLength = length ? length : stream.FileSize();
627
628
3.57k
    if (byteLength > stream.FileSize()) {
629
106
        throw DeadlyImportError("GLTF: Invalid byteLength exceeds size of actual data.");
630
106
    }
631
632
3.47k
    if (baseOffset) {
633
3.45k
        stream.Seek(baseOffset, aiOrigin_SET);
634
3.45k
    }
635
636
3.47k
    mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
637
638
3.47k
    if (stream.Read(mData.get(), byteLength, 1) != 1) {
639
30
        return false;
640
30
    }
641
3.44k
    return true;
642
3.47k
}
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
15.3k
inline void BufferView::Read(Value &obj, Asset &r) {
766
15.3k
    if (Value *bufferVal = FindUInt(obj, "buffer")) {
767
15.3k
        buffer = r.buffers.Retrieve(bufferVal->GetUint());
768
15.3k
    }
769
770
15.3k
    if (!buffer) {
771
14
        throw DeadlyImportError("GLTF: Buffer view without valid buffer.");
772
14
    }
773
774
15.3k
    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
775
15.3k
    byteLength = MemberOrDefault(obj, "byteLength", size_t(0));
776
15.3k
    byteStride = MemberOrDefault(obj, "byteStride", 0u);
777
778
    // Check length
779
15.3k
    if ((byteOffset + byteLength) > buffer->byteLength) {
780
57
        throw DeadlyImportError("GLTF: Buffer view with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
781
57
    }
782
15.3k
}
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
21.2k
inline void Accessor::Read(Value &obj, Asset &r) {
872
21.2k
    if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
873
16.2k
        bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
874
16.2k
    }
875
876
21.2k
    byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
877
21.2k
    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
878
21.2k
    {
879
21.2k
        const Value *countValue = FindUInt(obj, "count");
880
21.2k
        if (!countValue) {
881
22
            throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
882
22
        }
883
21.2k
        count = countValue->GetUint();
884
21.2k
    }
885
886
0
    const char *typestr;
887
21.2k
    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
888
889
21.2k
    if (bufferView) {
890
        // Check length
891
15.6k
        unsigned long long byteLength = count > 0
892
15.6k
            ? (unsigned long long)GetStride() * (unsigned long long)(count - 1) + (unsigned long long)GetElementSize()
893
15.6k
            : 0;
894
895
        // handle integer overflow
896
15.6k
        if (byteLength < count) {
897
0
            throw DeadlyImportError("GLTF: Accessor with offset/count (", byteOffset, "/", count, ") is out of range.");
898
0
        }
899
900
15.6k
        if ((byteOffset + byteLength) > bufferView->byteLength || (bufferView->byteOffset + byteOffset + byteLength) > bufferView->buffer->byteLength) {
901
138
            throw DeadlyImportError("GLTF: Accessor with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
902
138
        }
903
15.6k
    }
904
905
21.1k
    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
21.1k
}
958
959
51.0k
inline unsigned int Accessor::GetNumComponents() {
960
51.0k
    return AttribType::GetNumComponents(type);
961
51.0k
}
962
963
50.0k
inline unsigned int Accessor::GetBytesPerComponent() {
964
50.0k
    return int(ComponentTypeSize(componentType));
965
50.0k
}
966
967
50.0k
inline unsigned int Accessor::GetElementSize() {
968
50.0k
    return GetNumComponents() * GetBytesPerComponent();
969
50.0k
}
970
971
13.2k
inline uint8_t *Accessor::GetPointer() {
972
13.2k
    if (decodedBuffer)
973
0
        return decodedBuffer->GetPointer();
974
975
13.2k
    if (sparse)
976
0
        return sparse->data.data();
977
978
13.2k
    if (!bufferView || !bufferView->buffer) return nullptr;
979
13.0k
    uint8_t *basePtr = bufferView->buffer->GetPointer();
980
13.0k
    if (!basePtr) return nullptr;
981
982
13.0k
    size_t offset = byteOffset + bufferView->byteOffset;
983
984
    // Check if region is encoded.
985
13.0k
    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
13.0k
    return basePtr + offset;
994
13.0k
}
995
996
28.7k
inline size_t Accessor::GetStride() {
997
    // Decoded buffer is always packed
998
28.7k
    if (decodedBuffer)
999
0
        return GetElementSize();
1000
1001
    // Sparse and normal bufferView
1002
28.7k
    return (bufferView && bufferView->byteStride ? bufferView->byteStride : GetElementSize());
1003
28.7k
}
1004
1005
70.9k
inline size_t Accessor::GetMaxByteSize() {
1006
70.9k
    if (decodedBuffer)
1007
0
        return decodedBuffer->byteLength;
1008
1009
70.9k
    if (sparse) {
1010
0
        return sparse->data.size();
1011
0
    }
1012
1013
70.9k
    if (bufferView) {
1014
70.9k
        return byteOffset <= bufferView->byteLength ? bufferView->byteLength - byteOffset : 0;
1015
70.9k
    }
1016
1017
0
    return 0;
1018
70.9k
}
1019
1020
template <class T>
1021
10.7k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
10.7k
    uint8_t *data = GetPointer();
1023
10.7k
    if (!data) {
1024
106
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
106
    }
1026
1027
10.6k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
10.6k
    const size_t elemSize = GetElementSize();
1029
10.6k
    const size_t totalSize = elemSize * usedCount;
1030
1031
10.6k
    const size_t stride = GetStride();
1032
1033
10.6k
    const size_t targetElemSize = sizeof(T);
1034
1035
10.6k
    if (elemSize > targetElemSize) {
1036
40
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
40
    }
1038
1039
10.6k
    const size_t maxSize = GetMaxByteSize();
1040
1041
10.6k
    outData = new T[usedCount];
1042
1043
10.6k
    if (remappingIndices != nullptr) {
1044
7.29k
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
48.9k
        for (size_t i = 0; i < usedCount; ++i) {
1046
41.6k
            size_t srcIdx = (*remappingIndices)[i];
1047
41.6k
            if (srcIdx >= maxIndexCount) {
1048
2
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
2
            }
1050
41.6k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
41.6k
        }
1052
7.29k
    } else { // non-indexed cases
1053
3.30k
        if (usedCount * stride > maxSize) {
1054
5
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
5
        }
1056
3.30k
        if (stride == elemSize && targetElemSize == elemSize) {
1057
1.59k
            memcpy(outData, data, totalSize);
1058
1.71k
        } else {
1059
53.3k
            for (size_t i = 0; i < usedCount; ++i) {
1060
51.6k
                memcpy(outData + i, data + i * stride, elemSize);
1061
51.6k
            }
1062
1.71k
        }
1063
3.30k
    }
1064
10.5k
    return usedCount;
1065
10.6k
}
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.40k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
1.40k
    uint8_t *data = GetPointer();
1023
1.40k
    if (!data) {
1024
15
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
15
    }
1026
1027
1.39k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
1.39k
    const size_t elemSize = GetElementSize();
1029
1.39k
    const size_t totalSize = elemSize * usedCount;
1030
1031
1.39k
    const size_t stride = GetStride();
1032
1033
1.39k
    const size_t targetElemSize = sizeof(T);
1034
1035
1.39k
    if (elemSize > targetElemSize) {
1036
2
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
2
    }
1038
1039
1.38k
    const size_t maxSize = GetMaxByteSize();
1040
1041
1.38k
    outData = new T[usedCount];
1042
1043
1.38k
    if (remappingIndices != nullptr) {
1044
1.12k
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
5.48k
        for (size_t i = 0; i < usedCount; ++i) {
1046
4.36k
            size_t srcIdx = (*remappingIndices)[i];
1047
4.36k
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
4.36k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
4.36k
        }
1052
1.12k
    } else { // non-indexed cases
1053
267
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
267
        if (stride == elemSize && targetElemSize == elemSize) {
1057
217
            memcpy(outData, data, totalSize);
1058
217
        } else {
1059
302
            for (size_t i = 0; i < usedCount; ++i) {
1060
252
                memcpy(outData + i, data + i * stride, elemSize);
1061
252
            }
1062
50
        }
1063
267
    }
1064
1.38k
    return usedCount;
1065
1.38k
}
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
136
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
136
    uint8_t *data = GetPointer();
1023
136
    if (!data) {
1024
13
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
13
    }
1026
1027
123
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
123
    const size_t elemSize = GetElementSize();
1029
123
    const size_t totalSize = elemSize * usedCount;
1030
1031
123
    const size_t stride = GetStride();
1032
1033
123
    const size_t targetElemSize = sizeof(T);
1034
1035
123
    if (elemSize > targetElemSize) {
1036
21
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
21
    }
1038
1039
102
    const size_t maxSize = GetMaxByteSize();
1040
1041
102
    outData = new T[usedCount];
1042
1043
102
    if (remappingIndices != nullptr) {
1044
48
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
306
        for (size_t i = 0; i < usedCount; ++i) {
1046
258
            size_t srcIdx = (*remappingIndices)[i];
1047
258
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
258
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
258
        }
1052
54
    } else { // non-indexed cases
1053
54
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
54
        if (stride == elemSize && targetElemSize == elemSize) {
1057
35
            memcpy(outData, data, totalSize);
1058
35
        } else {
1059
119
            for (size_t i = 0; i < usedCount; ++i) {
1060
100
                memcpy(outData + i, data + i * stride, elemSize);
1061
100
            }
1062
19
        }
1063
54
    }
1064
102
    return usedCount;
1065
102
}
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.21k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
1.21k
    uint8_t *data = GetPointer();
1023
1.21k
    if (!data) {
1024
16
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
16
    }
1026
1027
1.19k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
1.19k
    const size_t elemSize = GetElementSize();
1029
1.19k
    const size_t totalSize = elemSize * usedCount;
1030
1031
1.19k
    const size_t stride = GetStride();
1032
1033
1.19k
    const size_t targetElemSize = sizeof(T);
1034
1035
1.19k
    if (elemSize > targetElemSize) {
1036
7
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
7
    }
1038
1039
1.18k
    const size_t maxSize = GetMaxByteSize();
1040
1041
1.18k
    outData = new T[usedCount];
1042
1043
1.18k
    if (remappingIndices != nullptr) {
1044
1.01k
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
4.89k
        for (size_t i = 0; i < usedCount; ++i) {
1046
3.87k
            size_t srcIdx = (*remappingIndices)[i];
1047
3.87k
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
3.87k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
3.87k
        }
1052
1.01k
    } else { // non-indexed cases
1053
170
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
170
        if (stride == elemSize && targetElemSize == elemSize) {
1057
121
            memcpy(outData, data, totalSize);
1058
121
        } else {
1059
315
            for (size_t i = 0; i < usedCount; ++i) {
1060
266
                memcpy(outData + i, data + i * stride, elemSize);
1061
266
            }
1062
49
        }
1063
170
    }
1064
1.18k
    return usedCount;
1065
1.18k
}
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.68k
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
6.68k
    uint8_t *data = GetPointer();
1023
6.68k
    if (!data) {
1024
28
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
28
    }
1026
1027
6.65k
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
6.65k
    const size_t elemSize = GetElementSize();
1029
6.65k
    const size_t totalSize = elemSize * usedCount;
1030
1031
6.65k
    const size_t stride = GetStride();
1032
1033
6.65k
    const size_t targetElemSize = sizeof(T);
1034
1035
6.65k
    if (elemSize > targetElemSize) {
1036
5
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
5
    }
1038
1039
6.65k
    const size_t maxSize = GetMaxByteSize();
1040
1041
6.65k
    outData = new T[usedCount];
1042
1043
6.65k
    if (remappingIndices != nullptr) {
1044
4.71k
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
36.4k
        for (size_t i = 0; i < usedCount; ++i) {
1046
31.7k
            size_t srcIdx = (*remappingIndices)[i];
1047
31.7k
            if (srcIdx >= maxIndexCount) {
1048
2
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
2
            }
1050
31.7k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
31.7k
        }
1052
4.71k
    } else { // non-indexed cases
1053
1.93k
        if (usedCount * stride > maxSize) {
1054
4
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
4
        }
1056
1.93k
        if (stride == elemSize && targetElemSize == elemSize) {
1057
631
            memcpy(outData, data, totalSize);
1058
1.29k
        } else {
1059
48.0k
            for (size_t i = 0; i < usedCount; ++i) {
1060
46.7k
                memcpy(outData + i, data + i * stride, elemSize);
1061
46.7k
            }
1062
1.29k
        }
1063
1.93k
    }
1064
6.64k
    return usedCount;
1065
6.65k
}
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
37
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
37
    uint8_t *data = GetPointer();
1023
37
    if (!data) {
1024
1
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
1
    }
1026
1027
36
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
36
    const size_t elemSize = GetElementSize();
1029
36
    const size_t totalSize = elemSize * usedCount;
1030
1031
36
    const size_t stride = GetStride();
1032
1033
36
    const size_t targetElemSize = sizeof(T);
1034
1035
36
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
36
    const size_t maxSize = GetMaxByteSize();
1040
1041
36
    outData = new T[usedCount];
1042
1043
36
    if (remappingIndices != nullptr) {
1044
23
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
164
        for (size_t i = 0; i < usedCount; ++i) {
1046
141
            size_t srcIdx = (*remappingIndices)[i];
1047
141
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
141
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
141
        }
1052
23
    } else { // non-indexed cases
1053
13
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
13
        if (stride == elemSize && targetElemSize == elemSize) {
1057
3
            memcpy(outData, data, totalSize);
1058
10
        } else {
1059
250
            for (size_t i = 0; i < usedCount; ++i) {
1060
240
                memcpy(outData + i, data + i * stride, elemSize);
1061
240
            }
1062
10
        }
1063
13
    }
1064
36
    return usedCount;
1065
36
}
unsigned long glTF2::Accessor::ExtractData<aiColor4t<float> >(aiColor4t<float>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
464
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
464
    uint8_t *data = GetPointer();
1023
464
    if (!data) {
1024
5
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
5
    }
1026
1027
459
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
459
    const size_t elemSize = GetElementSize();
1029
459
    const size_t totalSize = elemSize * usedCount;
1030
1031
459
    const size_t stride = GetStride();
1032
1033
459
    const size_t targetElemSize = sizeof(T);
1034
1035
459
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
459
    const size_t maxSize = GetMaxByteSize();
1040
1041
459
    outData = new T[usedCount];
1042
1043
459
    if (remappingIndices != nullptr) {
1044
364
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
1.68k
        for (size_t i = 0; i < usedCount; ++i) {
1046
1.31k
            size_t srcIdx = (*remappingIndices)[i];
1047
1.31k
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
1.31k
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
1.31k
        }
1052
364
    } else { // non-indexed cases
1053
95
        if (usedCount * stride > maxSize) {
1054
1
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
1
        }
1056
94
        if (stride == elemSize && targetElemSize == elemSize) {
1057
58
            memcpy(outData, data, totalSize);
1058
58
        } else {
1059
780
            for (size_t i = 0; i < usedCount; ++i) {
1060
744
                memcpy(outData + i, data + i * stride, elemSize);
1061
744
            }
1062
36
        }
1063
94
    }
1064
458
    return usedCount;
1065
459
}
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
16
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
16
    uint8_t *data = GetPointer();
1023
16
    if (!data) {
1024
2
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
2
    }
1026
1027
14
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
14
    const size_t elemSize = GetElementSize();
1029
14
    const size_t totalSize = elemSize * usedCount;
1030
1031
14
    const size_t stride = GetStride();
1032
1033
14
    const size_t targetElemSize = sizeof(T);
1034
1035
14
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
14
    const size_t maxSize = GetMaxByteSize();
1040
1041
14
    outData = new T[usedCount];
1042
1043
14
    if (remappingIndices != nullptr) {
1044
1
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
5
        for (size_t i = 0; i < usedCount; ++i) {
1046
4
            size_t srcIdx = (*remappingIndices)[i];
1047
4
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
4
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
4
        }
1052
13
    } else { // non-indexed cases
1053
13
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
13
        if (stride == elemSize && targetElemSize == elemSize) {
1057
0
            memcpy(outData, data, totalSize);
1058
13
        } else {
1059
65
            for (size_t i = 0; i < usedCount; ++i) {
1060
52
                memcpy(outData + i, data + i * stride, elemSize);
1061
52
            }
1062
13
        }
1063
13
    }
1064
14
    return usedCount;
1065
14
}
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
17
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
17
    uint8_t *data = GetPointer();
1023
17
    if (!data) {
1024
2
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
2
    }
1026
1027
15
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
15
    const size_t elemSize = GetElementSize();
1029
15
    const size_t totalSize = elemSize * usedCount;
1030
1031
15
    const size_t stride = GetStride();
1032
1033
15
    const size_t targetElemSize = sizeof(T);
1034
1035
15
    if (elemSize > targetElemSize) {
1036
0
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
0
    }
1038
1039
15
    const size_t maxSize = GetMaxByteSize();
1040
1041
15
    outData = new T[usedCount];
1042
1043
15
    if (remappingIndices != nullptr) {
1044
5
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
25
        for (size_t i = 0; i < usedCount; ++i) {
1046
20
            size_t srcIdx = (*remappingIndices)[i];
1047
20
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
20
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
20
        }
1052
10
    } else { // non-indexed cases
1053
10
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
10
        if (stride == elemSize && targetElemSize == elemSize) {
1057
8
            memcpy(outData, data, totalSize);
1058
8
        } else {
1059
10
            for (size_t i = 0; i < usedCount; ++i) {
1060
8
                memcpy(outData + i, data + i * stride, elemSize);
1061
8
            }
1062
2
        }
1063
10
    }
1064
15
    return usedCount;
1065
15
}
unsigned long glTF2::Accessor::ExtractData<float [16]>(float (*&) [16], std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
545
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
545
    uint8_t *data = GetPointer();
1023
545
    if (!data) {
1024
19
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
19
    }
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
    outData = new T[usedCount];
1042
1043
526
    if (remappingIndices != nullptr) {
1044
0
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
0
        for (size_t i = 0; i < usedCount; ++i) {
1046
0
            size_t srcIdx = (*remappingIndices)[i];
1047
0
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
0
        }
1052
526
    } else { // non-indexed cases
1053
526
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
526
        if (stride == elemSize && targetElemSize == elemSize) {
1057
402
            memcpy(outData, data, totalSize);
1058
402
        } else {
1059
1.69k
            for (size_t i = 0; i < usedCount; ++i) {
1060
1.56k
                memcpy(outData + i, data + i * stride, elemSize);
1061
1.56k
            }
1062
124
        }
1063
526
    }
1064
526
    return usedCount;
1065
526
}
unsigned long glTF2::Accessor::ExtractData<float>(float*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
120
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
120
    uint8_t *data = GetPointer();
1023
120
    if (!data) {
1024
1
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
1
    }
1026
1027
119
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
119
    const size_t elemSize = GetElementSize();
1029
119
    const size_t totalSize = elemSize * usedCount;
1030
1031
119
    const size_t stride = GetStride();
1032
1033
119
    const size_t targetElemSize = sizeof(T);
1034
1035
119
    if (elemSize > targetElemSize) {
1036
3
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
3
    }
1038
1039
116
    const size_t maxSize = GetMaxByteSize();
1040
1041
116
    outData = new T[usedCount];
1042
1043
116
    if (remappingIndices != nullptr) {
1044
0
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
0
        for (size_t i = 0; i < usedCount; ++i) {
1046
0
            size_t srcIdx = (*remappingIndices)[i];
1047
0
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
0
        }
1052
116
    } else { // non-indexed cases
1053
116
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
116
        if (stride == elemSize && targetElemSize == elemSize) {
1057
84
            memcpy(outData, data, totalSize);
1058
84
        } else {
1059
370
            for (size_t i = 0; i < usedCount; ++i) {
1060
338
                memcpy(outData + i, data + i * stride, elemSize);
1061
338
            }
1062
32
        }
1063
116
    }
1064
116
    return usedCount;
1065
116
}
unsigned long glTF2::Accessor::ExtractData<vec4f>(vec4f*&, 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
3
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
3
    }
1026
1027
38
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
38
    const size_t elemSize = GetElementSize();
1029
38
    const size_t totalSize = elemSize * usedCount;
1030
1031
38
    const size_t stride = GetStride();
1032
1033
38
    const size_t targetElemSize = sizeof(T);
1034
1035
38
    if (elemSize > targetElemSize) {
1036
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
1
    }
1038
1039
37
    const size_t maxSize = GetMaxByteSize();
1040
1041
37
    outData = new T[usedCount];
1042
1043
37
    if (remappingIndices != nullptr) {
1044
0
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
0
        for (size_t i = 0; i < usedCount; ++i) {
1046
0
            size_t srcIdx = (*remappingIndices)[i];
1047
0
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
0
        }
1052
37
    } else { // non-indexed cases
1053
37
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
37
        if (stride == elemSize && targetElemSize == elemSize) {
1057
6
            memcpy(outData, data, totalSize);
1058
31
        } else {
1059
575
            for (size_t i = 0; i < usedCount; ++i) {
1060
544
                memcpy(outData + i, data + i * stride, elemSize);
1061
544
            }
1062
31
        }
1063
37
    }
1064
37
    return usedCount;
1065
37
}
unsigned long glTF2::Accessor::ExtractData<aiQuaterniont<float> >(aiQuaterniont<float>*&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const*)
Line
Count
Source
1021
74
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
1022
74
    uint8_t *data = GetPointer();
1023
74
    if (!data) {
1024
1
        throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
1025
1
    }
1026
1027
73
    const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
1028
73
    const size_t elemSize = GetElementSize();
1029
73
    const size_t totalSize = elemSize * usedCount;
1030
1031
73
    const size_t stride = GetStride();
1032
1033
73
    const size_t targetElemSize = sizeof(T);
1034
1035
73
    if (elemSize > targetElemSize) {
1036
1
        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
1037
1
    }
1038
1039
72
    const size_t maxSize = GetMaxByteSize();
1040
1041
72
    outData = new T[usedCount];
1042
1043
72
    if (remappingIndices != nullptr) {
1044
0
        const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
1045
0
        for (size_t i = 0; i < usedCount; ++i) {
1046
0
            size_t srcIdx = (*remappingIndices)[i];
1047
0
            if (srcIdx >= maxIndexCount) {
1048
0
                throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1049
0
            }
1050
0
            memcpy(outData + i, data + srcIdx * stride, elemSize);
1051
0
        }
1052
72
    } else { // non-indexed cases
1053
72
        if (usedCount * stride > maxSize) {
1054
0
            throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
1055
0
        }
1056
72
        if (stride == elemSize && targetElemSize == elemSize) {
1057
25
            memcpy(outData, data, totalSize);
1058
47
        } else {
1059
868
            for (size_t i = 0; i < usedCount; ++i) {
1060
821
                memcpy(outData + i, data + i * stride, elemSize);
1061
821
            }
1062
47
        }
1063
72
    }
1064
72
    return usedCount;
1065
72
}
1066
1067
0
inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) {
1068
0
    uint8_t *buffer_ptr = bufferView->buffer->GetPointer();
1069
0
    size_t offset = byteOffset + bufferView->byteOffset;
1070
0
1071
0
    size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
1072
0
1073
0
    const uint8_t *src = reinterpret_cast<const uint8_t *>(src_buffer);
1074
0
    uint8_t *dst = reinterpret_cast<uint8_t *>(buffer_ptr + offset);
1075
0
1076
0
    ai_assert(dst + _count * dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
1077
0
    CopyData(_count, src, src_stride, dst, dst_stride);
1078
0
}
1079
1080
0
inline void Accessor::WriteSparseValues(size_t _count, const void *src_data, size_t src_dataStride) {
1081
0
    if (!sparse)
1082
0
        return;
1083
0
1084
0
    // values
1085
0
    uint8_t *value_buffer_ptr = sparse->values->buffer->GetPointer();
1086
0
    size_t value_offset = sparse->valuesByteOffset + sparse->values->byteOffset;
1087
0
    size_t value_dst_stride = GetNumComponents() * GetBytesPerComponent();
1088
0
    const uint8_t *value_src = reinterpret_cast<const uint8_t *>(src_data);
1089
0
    uint8_t *value_dst = reinterpret_cast<uint8_t *>(value_buffer_ptr + value_offset);
1090
0
    ai_assert(value_dst + _count * value_dst_stride <= value_buffer_ptr + sparse->values->buffer->byteLength);
1091
0
    CopyData(_count, value_src, src_dataStride, value_dst, value_dst_stride);
1092
0
}
1093
1094
0
inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, size_t src_idxStride) {
1095
0
    if (!sparse)
1096
0
        return;
1097
0
1098
0
    // indices
1099
0
    uint8_t *indices_buffer_ptr = sparse->indices->buffer->GetPointer();
1100
0
    size_t indices_offset = sparse->indicesByteOffset + sparse->indices->byteOffset;
1101
0
    size_t indices_dst_stride = 1 * sizeof(unsigned short);
1102
0
    const uint8_t *indices_src = reinterpret_cast<const uint8_t *>(src_idx);
1103
0
    uint8_t *indices_dst = reinterpret_cast<uint8_t *>(indices_buffer_ptr + indices_offset);
1104
0
    ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
1105
0
    CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
1106
0
}
1107
1108
inline Accessor::Indexer::Indexer(Accessor &acc) :
1109
2.47k
    accessor(acc),
1110
2.47k
    data(acc.GetPointer()),
1111
2.47k
    elemSize(acc.GetElementSize()),
1112
2.47k
    stride(acc.GetStride()) {
1113
2.47k
}
1114
1115
//! Accesses the i-th value as defined by the accessor
1116
template <class T>
1117
60.3k
T Accessor::Indexer::GetValue(int i) {
1118
60.3k
    ai_assert(data);
1119
60.3k
    if (i * stride >= accessor.GetMaxByteSize()) {
1120
1
        throw DeadlyImportError("GLTF: Invalid index ", i, ", count out of range for buffer with stride ", stride, " and size ", accessor.GetMaxByteSize(), ".");
1121
1
    }
1122
    // Ensure that the memcpy doesn't overwrite the local.
1123
60.3k
    const size_t sizeToCopy = std::min(elemSize, sizeof(T));
1124
60.3k
    T value = T();
1125
    // Assume platform endianness matches GLTF binary data (which is little-endian).
1126
60.3k
    memcpy(&value, data + i * stride, sizeToCopy);
1127
60.3k
    return value;
1128
60.3k
}
1129
1130
inline Image::Image() :
1131
258
        width(0),
1132
258
        height(0),
1133
258
        mDataLength(0) {
1134
258
}
1135
1136
258
inline void Image::Read(Value &obj, Asset &r) {
1137
    //basisu: no need to handle .ktx2, .basis, load as is
1138
258
    if (!mDataLength) {
1139
258
        Value *curUri = FindString(obj, "uri");
1140
258
        if (nullptr != curUri) {
1141
129
            const char *uristr = curUri->GetString();
1142
1143
129
            glTFCommon::Util::DataURI dataURI;
1144
129
            if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
1145
108
                mimeType = dataURI.mediaType;
1146
108
                if (dataURI.base64) {
1147
101
                    uint8_t *ptr = nullptr;
1148
101
                    mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr);
1149
101
                    mData.reset(ptr);
1150
101
                }
1151
108
            } else {
1152
21
                this->uri = uristr;
1153
21
            }
1154
129
        } else if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
1155
124
            this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
1156
124
            if (Value *mtype = FindString(obj, "mimeType")) {
1157
119
                this->mimeType = mtype->GetString();
1158
119
            }
1159
124
            if (!this->bufferView || this->mimeType.empty()) {
1160
2
                throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " does not have a URI, so it must have a valid bufferView and mimetype");
1161
2
            }
1162
1163
122
            Ref<Buffer> buffer = this->bufferView->buffer;
1164
1165
122
            this->mDataLength = this->bufferView->byteLength;
1166
            // maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
1167
1168
122
            this->mData.reset(new uint8_t[this->mDataLength]);
1169
122
            memcpy(this->mData.get(), buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
1170
122
        } else {
1171
5
            throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " should have either a URI of a bufferView and mimetype");
1172
5
        }
1173
258
    }
1174
258
}
1175
1176
165
inline uint8_t *Image::StealData() {
1177
165
    mDataLength = 0;
1178
165
    return mData.release();
1179
165
}
1180
1181
// Never take over the ownership of data whenever binary or not
1182
0
inline void Image::SetData(uint8_t *data, size_t length, Asset &r) {
1183
0
    Ref<Buffer> b = r.GetBodyBuffer();
1184
0
    if (b) { // binary file: append to body
1185
0
        std::string bvId = r.FindUniqueID(this->id, "imgdata");
1186
0
        bufferView = r.bufferViews.Create(bvId);
1187
0
1188
0
        bufferView->buffer = b;
1189
0
        bufferView->byteLength = length;
1190
0
        bufferView->byteOffset = b->AppendData(data, length);
1191
0
    } else { // text file: will be stored as a data uri
1192
0
        uint8_t *temp = new uint8_t[length];
1193
0
        memcpy(temp, data, length);
1194
0
        this->mData.reset(temp);
1195
0
        this->mDataLength = length;
1196
0
    }
1197
0
}
1198
1199
224
inline void Sampler::Read(Value &obj, Asset & /*r*/) {
1200
224
    SetDefaults();
1201
1202
224
    ReadMember(obj, "name", name);
1203
224
    ReadMember(obj, "magFilter", magFilter);
1204
224
    ReadMember(obj, "minFilter", minFilter);
1205
224
    ReadMember(obj, "wrapS", wrapS);
1206
224
    ReadMember(obj, "wrapT", wrapT);
1207
224
}
1208
1209
448
inline void Sampler::SetDefaults() {
1210
    //only wrapping modes have defaults
1211
448
    wrapS = SamplerWrap::Repeat;
1212
448
    wrapT = SamplerWrap::Repeat;
1213
448
    magFilter = SamplerMagFilter::UNSET;
1214
448
    minFilter = SamplerMinFilter::UNSET;
1215
448
}
1216
1217
299
inline void Texture::Read(Value &obj, Asset &r) {
1218
299
    if (Value *sourceVal = FindUInt(obj, "source")) {
1219
268
        source = r.images.Retrieve(sourceVal->GetUint());
1220
268
    }
1221
1222
299
    if (Value *samplerVal = FindUInt(obj, "sampler")) {
1223
238
        sampler = r.samplers.Retrieve(samplerVal->GetUint());
1224
238
    }
1225
1226
299
    if (Value *extensions = FindObject(obj, "extensions")) {
1227
0
        if (r.extensionsUsed.KHR_texture_basisu) {
1228
0
            if (Value *curBasisU = FindObject(*extensions, "KHR_texture_basisu")) {
1229
1230
0
                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
1231
0
                    source = r.images.Retrieve(sourceVal->GetUint());
1232
0
                }
1233
0
            }
1234
0
        } else if(r.extensionsUsed.EXT_texture_webp) {
1235
0
            if (Value *curBasisU = FindObject(*extensions, "EXT_texture_webp")) {
1236
1237
0
                if (Value *sourceVal = FindUInt(*curBasisU, "source")) {
1238
0
                    source = r.images.Retrieve(sourceVal->GetUint());
1239
0
                }
1240
0
            }
1241
0
        }
1242
0
    }
1243
299
}
1244
1245
409
void Material::SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
1246
409
    if (r.extensionsUsed.KHR_texture_transform) {
1247
4
        if (Value *pKHR_texture_transform = FindExtension(*prop, "KHR_texture_transform")) {
1248
0
            out.textureTransformSupported = true;
1249
0
            if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
1250
0
                out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
1251
0
                out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
1252
0
            } else {
1253
0
                out.TextureTransformExt_t.offset[0] = 0;
1254
0
                out.TextureTransformExt_t.offset[1] = 0;
1255
0
            }
1256
1257
0
            if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
1258
0
                out.TextureTransformExt_t.rotation = 0;
1259
0
            }
1260
1261
0
            if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
1262
0
                out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
1263
0
                out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
1264
0
            } else {
1265
0
                out.TextureTransformExt_t.scale[0] = 1;
1266
0
                out.TextureTransformExt_t.scale[1] = 1;
1267
0
            }
1268
0
        }
1269
4
    }
1270
1271
409
    if (Value *indexProp = FindUInt(*prop, "index")) {
1272
400
        out.texture = r.textures.Retrieve(indexProp->GetUint());
1273
400
    }
1274
1275
409
    if (Value *texcoord = FindUInt(*prop, "texCoord")) {
1276
1
        out.texCoord = texcoord->GetUint();
1277
1
    }
1278
409
}
1279
1280
13.0k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
1281
13.0k
    if (Value *prop = FindMember(vals, propName)) {
1282
409
        SetTextureProperties(r, prop, out);
1283
409
    }
1284
13.0k
}
1285
1286
4.74k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
1287
4.74k
    if (Value *prop = FindMember(vals, propName)) {
1288
0
        SetTextureProperties(r, prop, out);
1289
1290
0
        if (Value *scale = FindNumber(*prop, "scale")) {
1291
0
            out.scale = static_cast<float>(scale->GetDouble());
1292
0
        }
1293
0
    }
1294
4.74k
}
1295
1296
4.74k
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
1297
4.74k
    if (Value *prop = FindMember(vals, propName)) {
1298
0
        SetTextureProperties(r, prop, out);
1299
1300
0
        if (Value *strength = FindNumber(*prop, "strength")) {
1301
0
            out.strength = static_cast<float>(strength->GetDouble());
1302
0
        }
1303
0
    }
1304
4.74k
}
1305
1306
4.80k
inline void Material::Read(Value &material, Asset &r) {
1307
4.80k
    SetDefaults();
1308
1309
4.80k
    if (Value *curPbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
1310
4.19k
        ReadMember(*curPbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
1311
4.19k
        ReadTextureProperty(r, *curPbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
1312
4.19k
        ReadTextureProperty(r, *curPbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
1313
4.19k
        ReadMember(*curPbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
1314
4.19k
        ReadMember(*curPbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
1315
4.19k
    }
1316
1317
4.80k
    ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
1318
4.80k
    ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
1319
4.80k
    ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
1320
4.80k
    ReadMember(material, "emissiveFactor", this->emissiveFactor);
1321
1322
4.80k
    ReadMember(material, "doubleSided", this->doubleSided);
1323
4.80k
    ReadMember(material, "alphaMode", this->alphaMode);
1324
4.80k
    ReadMember(material, "alphaCutoff", this->alphaCutoff);
1325
1326
4.80k
    if (Value *extensions = FindObject(material, "extensions")) {
1327
0
        if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
1328
0
            if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
1329
0
                PbrSpecularGlossiness pbrSG;
1330
1331
0
                ReadMember(*curPbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
1332
0
                ReadTextureProperty(r, *curPbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
1333
0
                ReadTextureProperty(r, *curPbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
1334
0
                ReadMember(*curPbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
1335
0
                ReadMember(*curPbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
1336
1337
0
                this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
1338
0
            }
1339
0
        }
1340
1341
0
        if (r.extensionsUsed.KHR_materials_specular) {
1342
0
            if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) {
1343
0
                MaterialSpecular specular;
1344
1345
0
                ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor);
1346
0
                ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture);
1347
0
                ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor);
1348
0
                ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture);
1349
1350
0
                this->materialSpecular = Nullable<MaterialSpecular>(specular);
1351
0
            }
1352
0
        }
1353
1354
        // Extension KHR_texture_transform is handled in ReadTextureProperty
1355
1356
0
        if (r.extensionsUsed.KHR_materials_sheen) {
1357
0
            if (Value *curMaterialSheen = FindObject(*extensions, "KHR_materials_sheen")) {
1358
0
                MaterialSheen sheen;
1359
1360
0
                ReadMember(*curMaterialSheen, "sheenColorFactor", sheen.sheenColorFactor);
1361
0
                ReadTextureProperty(r, *curMaterialSheen, "sheenColorTexture", sheen.sheenColorTexture);
1362
0
                ReadMember(*curMaterialSheen, "sheenRoughnessFactor", sheen.sheenRoughnessFactor);
1363
0
                ReadTextureProperty(r, *curMaterialSheen, "sheenRoughnessTexture", sheen.sheenRoughnessTexture);
1364
1365
0
                this->materialSheen = Nullable<MaterialSheen>(sheen);
1366
0
            }
1367
0
        }
1368
1369
0
        if (r.extensionsUsed.KHR_materials_clearcoat) {
1370
0
            if (Value *curMaterialClearcoat = FindObject(*extensions, "KHR_materials_clearcoat")) {
1371
0
                MaterialClearcoat clearcoat;
1372
1373
0
                ReadMember(*curMaterialClearcoat, "clearcoatFactor", clearcoat.clearcoatFactor);
1374
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatTexture", clearcoat.clearcoatTexture);
1375
0
                ReadMember(*curMaterialClearcoat, "clearcoatRoughnessFactor", clearcoat.clearcoatRoughnessFactor);
1376
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatRoughnessTexture", clearcoat.clearcoatRoughnessTexture);
1377
0
                ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatNormalTexture", clearcoat.clearcoatNormalTexture);
1378
1379
0
                this->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
1380
0
            }
1381
0
        }
1382
1383
0
        if (r.extensionsUsed.KHR_materials_transmission) {
1384
0
            if (Value *curMaterialTransmission = FindObject(*extensions, "KHR_materials_transmission")) {
1385
0
                MaterialTransmission transmission;
1386
1387
0
                ReadMember(*curMaterialTransmission, "transmissionFactor", transmission.transmissionFactor);
1388
0
                ReadTextureProperty(r, *curMaterialTransmission, "transmissionTexture", transmission.transmissionTexture);
1389
1390
0
                this->materialTransmission = Nullable<MaterialTransmission>(transmission);
1391
0
            }
1392
0
        }
1393
1394
0
        if (r.extensionsUsed.KHR_materials_volume) {
1395
0
            if (Value *curMaterialVolume = FindObject(*extensions, "KHR_materials_volume")) {
1396
0
                MaterialVolume volume;
1397
1398
0
                ReadMember(*curMaterialVolume, "thicknessFactor", volume.thicknessFactor);
1399
0
                ReadTextureProperty(r, *curMaterialVolume, "thicknessTexture", volume.thicknessTexture);
1400
0
                ReadMember(*curMaterialVolume, "attenuationDistance", volume.attenuationDistance);
1401
0
                ReadMember(*curMaterialVolume, "attenuationColor", volume.attenuationColor);
1402
1403
0
                this->materialVolume = Nullable<MaterialVolume>(volume);
1404
0
            }
1405
0
        }
1406
1407
0
        if (r.extensionsUsed.KHR_materials_ior) {
1408
0
            if (Value *curMaterialIOR = FindObject(*extensions, "KHR_materials_ior")) {
1409
0
                MaterialIOR ior;
1410
1411
0
                ReadMember(*curMaterialIOR, "ior", ior.ior);
1412
1413
0
                this->materialIOR = Nullable<MaterialIOR>(ior);
1414
0
            }
1415
0
        }
1416
1417
0
        if (r.extensionsUsed.KHR_materials_emissive_strength) {
1418
0
            if (Value *curMaterialEmissiveStrength = FindObject(*extensions, "KHR_materials_emissive_strength")) {
1419
0
                MaterialEmissiveStrength emissiveStrength;
1420
1421
0
                ReadMember(*curMaterialEmissiveStrength, "emissiveStrength", emissiveStrength.emissiveStrength);
1422
1423
0
                this->materialEmissiveStrength = Nullable<MaterialEmissiveStrength>(emissiveStrength);
1424
0
            }
1425
0
        }
1426
1427
0
        if (r.extensionsUsed.KHR_materials_anisotropy) {
1428
0
            if (Value *curMaterialAnisotropy = FindObject(*extensions, "KHR_materials_anisotropy")) {
1429
0
                MaterialAnisotropy anisotropy;
1430
1431
0
                ReadMember(*curMaterialAnisotropy, "anisotropyStrength", anisotropy.anisotropyStrength);
1432
0
                ReadMember(*curMaterialAnisotropy, "anisotropyRotation", anisotropy.anisotropyRotation);
1433
0
                ReadTextureProperty(r, *curMaterialAnisotropy, "anisotropyTexture", anisotropy.anisotropyTexture);
1434
1435
0
                this->materialAnisotropy = Nullable<MaterialAnisotropy>(anisotropy);
1436
0
            }
1437
0
        }
1438
1439
0
        unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
1440
0
    }
1441
4.80k
}
1442
1443
13.8k
inline void Material::SetDefaults() {
1444
    //pbr materials
1445
13.8k
    SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
1446
13.8k
    pbrMetallicRoughness.metallicFactor = 1.0f;
1447
13.8k
    pbrMetallicRoughness.roughnessFactor = 1.0f;
1448
1449
13.8k
    SetVector(emissiveFactor, defaultEmissiveFactor);
1450
13.8k
    alphaMode = "OPAQUE";
1451
13.8k
    alphaCutoff = 0.5f;
1452
13.8k
    doubleSided = false;
1453
13.8k
    unlit = false;
1454
13.8k
}
1455
1456
9.04k
inline void PbrSpecularGlossiness::SetDefaults() {
1457
    //pbrSpecularGlossiness properties
1458
9.04k
    SetVector(diffuseFactor, defaultDiffuseFactor);
1459
9.04k
    SetVector(specularFactor, defaultSpecularFactor);
1460
9.04k
    glossinessFactor = 1.0f;
1461
9.04k
}
1462
1463
9.04k
inline void MaterialSpecular::SetDefaults() {
1464
    //KHR_materials_specular properties
1465
9.04k
    SetVector(specularColorFactor, defaultSpecularColorFactor);
1466
9.04k
    specularFactor = 1.f;
1467
9.04k
}
1468
1469
9.04k
inline void MaterialSheen::SetDefaults() {
1470
    //KHR_materials_sheen properties
1471
9.04k
    SetVector(sheenColorFactor, defaultSheenFactor);
1472
9.04k
    sheenRoughnessFactor = 0.f;
1473
9.04k
}
1474
1475
9.04k
inline void MaterialVolume::SetDefaults() {
1476
    //KHR_materials_volume properties
1477
9.04k
    thicknessFactor = 0.f;
1478
9.04k
    attenuationDistance = std::numeric_limits<float>::infinity();
1479
9.04k
    SetVector(attenuationColor, defaultAttenuationColor);
1480
9.04k
}
1481
1482
9.04k
inline void MaterialIOR::SetDefaults() {
1483
    //KHR_materials_ior properties
1484
9.04k
    ior = 1.5f;
1485
9.04k
}
1486
1487
9.04k
inline void MaterialEmissiveStrength::SetDefaults() {
1488
    //KHR_materials_emissive_strength properties
1489
9.04k
    emissiveStrength = 0.f;
1490
9.04k
}
1491
1492
9.04k
inline void MaterialAnisotropy::SetDefaults() {
1493
    //KHR_materials_anisotropy properties
1494
9.04k
    anisotropyStrength = 0.f;
1495
9.04k
    anisotropyRotation = 0.f;
1496
9.04k
}
1497
1498
6.60k
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
1499
6.60k
    Value *curName = FindMember(pJSON_Object, "name");
1500
6.60k
    if (nullptr != curName && curName->IsString()) {
1501
4.91k
        name = curName->GetString();
1502
4.91k
    }
1503
1504
    /****************** Mesh primitives ******************/
1505
6.60k
    Value *curPrimitives = FindArray(pJSON_Object, "primitives");
1506
6.60k
    if (nullptr != curPrimitives) {
1507
6.20k
        this->primitives.resize(curPrimitives->Size());
1508
12.7k
        for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
1509
6.57k
            Value &primitive = (*curPrimitives)[i];
1510
1511
6.57k
            Primitive &prim = this->primitives[i];
1512
6.57k
            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
1513
1514
6.57k
            if (Value *indices = FindUInt(primitive, "indices")) {
1515
5.00k
                prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
1516
5.00k
            }
1517
1518
6.57k
            if (Value *material = FindUInt(primitive, "material")) {
1519
4.88k
                prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
1520
4.88k
            }
1521
1522
6.57k
            if (Value *attrs = FindObject(primitive, "attributes")) {
1523
22.7k
                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
1524
16.9k
                    if (!it->value.IsUint()) continue;
1525
16.9k
                    const char *attr = it->name.GetString();
1526
                    // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
1527
                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
1528
1529
16.9k
                    int undPos = 0;
1530
16.9k
                    Mesh::AccessorList *vec = nullptr;
1531
16.9k
                    if (GetAttribVector(prim, attr, vec, undPos)) {
1532
15.9k
                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1533
15.9k
                        if ((*vec).size() != idx) {
1534
46
                            throw DeadlyImportError("GLTF: Invalid attribute in mesh: ", name, " primitive: ", i, "attrib: ", attr,
1535
46
                                    ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
1536
46
                        }
1537
15.9k
                        (*vec).resize(idx + 1);
1538
15.9k
                        (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
1539
15.9k
                    }
1540
16.9k
                }
1541
5.83k
            }
1542
1543
#ifdef ASSIMP_ENABLE_DRACO
1544
            // KHR_draco_mesh_compression spec: Draco can only be used for glTF Triangles or Triangle Strips
1545
            if (pAsset_Root.extensionsUsed.KHR_draco_mesh_compression && (prim.mode == PrimitiveMode_TRIANGLES || prim.mode == PrimitiveMode_TRIANGLE_STRIP)) {
1546
                // Look for draco mesh compression extension and bufferView
1547
                // Skip if any missing
1548
                if (Value *dracoExt = FindExtension(primitive, "KHR_draco_mesh_compression")) {
1549
                    if (Value *bufView = FindUInt(*dracoExt, "bufferView")) {
1550
                        // Attempt to load indices and attributes using draco compression
1551
                        auto bufferView = pAsset_Root.bufferViews.Retrieve(bufView->GetUint());
1552
                        // Attempt to perform the draco decode on the buffer data
1553
                        const char *bufferViewData = reinterpret_cast<const char *>(bufferView->buffer->GetPointer() + bufferView->byteOffset);
1554
                        draco::DecoderBuffer decoderBuffer;
1555
                        decoderBuffer.Init(bufferViewData, bufferView->byteLength);
1556
                        draco::Decoder decoder;
1557
                        auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
1558
                        if (!decodeResult.ok()) {
1559
                            // A corrupt Draco isn't actually fatal if the primitive data is also provided in a standard buffer, but does anyone do that?
1560
                            throw DeadlyImportError("GLTF: Invalid Draco mesh compression in mesh: ", name, " primitive: ", i, ": ", decodeResult.status().error_msg_string());
1561
                        }
1562
1563
                        // Now we have a draco mesh
1564
                        const std::unique_ptr<draco::Mesh> &pDracoMesh = decodeResult.value();
1565
1566
                        // Redirect the accessors to the decoded data
1567
1568
                        // Indices
1569
                        SetDecodedIndexBuffer_Draco(*pDracoMesh, prim);
1570
1571
                        // Vertex attributes
1572
                        if (Value *attrs = FindObject(*dracoExt, "attributes")) {
1573
                            for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
1574
                                if (!it->value.IsUint()) continue;
1575
                                const char *attr = it->name.GetString();
1576
1577
                                int undPos = 0;
1578
                                Mesh::AccessorList *vec = nullptr;
1579
                                if (GetAttribVector(prim, attr, vec, undPos)) {
1580
                                    size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1581
                                    if (idx >= (*vec).size()) {
1582
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
1583
                                                ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
1584
                                    }
1585
1586
                                    if (!(*vec)[idx]) {
1587
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
1588
                                                ". All draco-encoded attributes must also define an accessor.");
1589
                                    }
1590
1591
                                    Accessor &attribAccessor = *(*vec)[idx];
1592
                                    if (attribAccessor.count == 0)
1593
                                        throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr);
1594
1595
                                    // Redirect this accessor to the appropriate Draco vertex attribute data
1596
                                    const uint32_t dracoAttribId = it->value.GetUint();
1597
                                    SetDecodedAttributeBuffer_Draco(*pDracoMesh, dracoAttribId, attribAccessor);
1598
                                }
1599
                            }
1600
                        }
1601
                    }
1602
                }
1603
            }
1604
#endif
1605
1606
6.52k
            Value *targetsArray = FindArray(primitive, "targets");
1607
6.52k
            if (nullptr != targetsArray) {
1608
20
                prim.targets.resize(targetsArray->Size());
1609
56
                for (unsigned int j = 0; j < targetsArray->Size(); ++j) {
1610
36
                    Value &target = (*targetsArray)[j];
1611
36
                    if (!target.IsObject()) {
1612
1
                        continue;
1613
1
                    }
1614
85
                    for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) {
1615
50
                        if (!it->value.IsUint()) {
1616
6
                            continue;
1617
6
                        }
1618
44
                        const char *attr = it->name.GetString();
1619
                        // Valid attribute semantics include POSITION, NORMAL, TANGENT
1620
44
                        int undPos = 0;
1621
44
                        Mesh::AccessorList *vec = nullptr;
1622
44
                        if (GetAttribTargetVector(prim, j, attr, vec, undPos)) {
1623
20
                            size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
1624
20
                            if ((*vec).size() <= idx) {
1625
17
                                (*vec).resize(idx + 1);
1626
17
                            }
1627
20
                            (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
1628
20
                        }
1629
44
                    }
1630
35
                }
1631
20
            }
1632
1633
6.52k
            if(this->targetNames.empty())
1634
5.60k
            {
1635
5.60k
                Value *curExtras = FindObject(primitive, "extras");
1636
5.60k
                if (nullptr != curExtras) {
1637
1
                    if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
1638
0
                        this->targetNames.resize(curTargetNames->Size());
1639
0
                        for (unsigned int j = 0; j < curTargetNames->Size(); ++j) {
1640
0
                            Value &targetNameValue = (*curTargetNames)[j];
1641
0
                            if (targetNameValue.IsString()) {
1642
0
                                this->targetNames[j] = targetNameValue.GetString();
1643
0
                            }
1644
0
                        }
1645
0
                    }
1646
1
                }
1647
5.60k
            }
1648
6.52k
        }
1649
6.20k
    }
1650
1651
6.55k
    Value *curWeights = FindArray(pJSON_Object, "weights");
1652
6.55k
    if (nullptr != curWeights) {
1653
13
        this->weights.resize(curWeights->Size());
1654
40
        for (unsigned int i = 0; i < curWeights->Size(); ++i) {
1655
27
            Value &weightValue = (*curWeights)[i];
1656
27
            if (weightValue.IsNumber()) {
1657
27
                this->weights[i] = weightValue.GetFloat();
1658
27
            }
1659
27
        }
1660
13
    }
1661
1662
6.55k
    Value *curExtras = FindObject(pJSON_Object, "extras");
1663
6.55k
    if (nullptr != curExtras) {
1664
0
        if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
1665
0
            this->targetNames.resize(curTargetNames->Size());
1666
0
            for (unsigned int i = 0; i < curTargetNames->Size(); ++i) {
1667
0
                Value &targetNameValue = (*curTargetNames)[i];
1668
0
                if (targetNameValue.IsString()) {
1669
0
                    this->targetNames[i] = targetNameValue.GetString();
1670
0
                }
1671
0
            }
1672
0
        }
1673
0
    }
1674
6.55k
}
1675
1676
110
inline void Camera::Read(Value &obj, Asset & /*r*/) {
1677
110
    std::string type_string = std::string(MemberOrDefault(obj, "type", "perspective"));
1678
110
    if (type_string == "orthographic") {
1679
20
        type = Camera::Orthographic;
1680
90
    } else {
1681
90
        type = Camera::Perspective;
1682
90
    }
1683
1684
110
    const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
1685
1686
110
    Value *it = FindObject(obj, subobjId);
1687
110
    if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
1688
1689
99
    if (type == Camera::Perspective) {
1690
79
        cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
1691
79
        cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f / 2.f);
1692
79
        cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
1693
79
        cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
1694
79
    } else {
1695
20
        cameraProperties.ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
1696
20
        cameraProperties.ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
1697
20
        cameraProperties.ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
1698
20
        cameraProperties.ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
1699
20
    }
1700
99
}
1701
1702
0
inline void Light::Read(Value &obj, Asset & /*r*/) {
1703
#ifndef M_PI
1704
    const float M_PI = 3.14159265358979323846f;
1705
#endif
1706
1707
0
    std::string type_string;
1708
0
    ReadMember(obj, "type", type_string);
1709
0
    if (type_string == "directional")
1710
0
        type = Light::Directional;
1711
0
    else if (type_string == "point")
1712
0
        type = Light::Point;
1713
0
    else
1714
0
        type = Light::Spot;
1715
1716
0
    name = MemberOrDefault(obj, "name", "");
1717
1718
0
    SetVector(color, vec3{ 1.0f, 1.0f, 1.0f });
1719
0
    ReadMember(obj, "color", color);
1720
1721
0
    intensity = MemberOrDefault(obj, "intensity", 1.0f);
1722
1723
0
    ReadMember(obj, "range", range);
1724
1725
0
    if (type == Light::Spot) {
1726
0
        Value *spot = FindObject(obj, "spot");
1727
0
        if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters");
1728
0
        innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f);
1729
0
        outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", static_cast<float>(M_PI / 4.0f));
1730
0
    }
1731
0
}
1732
1733
27.4k
inline void Node::Read(Value &obj, Asset &r) {
1734
27.4k
    if (name.empty()) {
1735
8.95k
        name = id;
1736
8.95k
    }
1737
1738
27.4k
    Value *curChildren = FindArray(obj, "children");
1739
27.4k
    if (nullptr != curChildren) {
1740
11.9k
        this->children.reserve(curChildren->Size());
1741
33.6k
        for (unsigned int i = 0; i < curChildren->Size(); ++i) {
1742
21.7k
            Value &child = (*curChildren)[i];
1743
21.7k
            if (child.IsUint()) {
1744
                // get/create the child node
1745
21.1k
                Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
1746
21.1k
                if (chn) {
1747
20.3k
                    this->children.push_back(chn);
1748
20.3k
                }
1749
21.1k
            }
1750
21.7k
        }
1751
11.9k
    }
1752
1753
27.4k
    Value *curMatrix = FindArray(obj, "matrix");
1754
27.4k
    if (nullptr != curMatrix) {
1755
19.0k
        ReadValue(*curMatrix, this->matrix);
1756
19.0k
    } else {
1757
8.32k
        ReadMember(obj, "translation", translation);
1758
8.32k
        ReadMember(obj, "scale", scale);
1759
8.32k
        ReadMember(obj, "rotation", rotation);
1760
8.32k
    }
1761
1762
27.4k
    Value *curMesh = FindUInt(obj, "mesh");
1763
27.4k
    if (nullptr != curMesh) {
1764
8.56k
        unsigned int numMeshes = 1;
1765
8.56k
        this->meshes.reserve(numMeshes);
1766
8.56k
        Ref<Mesh> meshRef = r.meshes.Retrieve((*curMesh).GetUint());
1767
8.56k
        if (meshRef) {
1768
7.51k
            this->meshes.push_back(meshRef);
1769
7.51k
        }
1770
8.56k
    }
1771
1772
    // Do not retrieve a skin here, just take a reference, to avoid infinite recursion
1773
    // Skins will be properly loaded later
1774
27.4k
    Value *curSkin = FindUInt(obj, "skin");
1775
27.4k
    if (nullptr != curSkin) {
1776
967
        this->skin = r.skins.Get(curSkin->GetUint());
1777
967
    }
1778
1779
27.4k
    Value *curCamera = FindUInt(obj, "camera");
1780
27.4k
    if (nullptr != curCamera) {
1781
130
        this->camera = r.cameras.Retrieve(curCamera->GetUint());
1782
130
        if (this->camera) {
1783
103
            this->camera->id = this->id;
1784
103
        }
1785
130
    }
1786
1787
27.4k
    Value *curExtensions = FindObject(obj, "extensions");
1788
27.4k
    if (nullptr != curExtensions) {
1789
0
        if (r.extensionsUsed.KHR_lights_punctual) {
1790
0
            if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
1791
0
                Value *curLight = FindUInt(*ext, "light");
1792
0
                if (nullptr != curLight) {
1793
0
                    this->light = r.lights.Retrieve(curLight->GetUint());
1794
0
                    if (this->light) {
1795
0
                        this->light->id = this->id;
1796
0
                    }
1797
0
                }
1798
0
            }
1799
0
        }
1800
0
    }
1801
27.4k
}
1802
1803
5.44k
inline void Scene::Read(Value &obj, Asset &r) {
1804
5.44k
    if (Value *scene_name = FindString(obj, "name")) {
1805
177
        if (scene_name->IsString()) {
1806
177
            this->name = scene_name->GetString();
1807
177
        }
1808
177
    }
1809
5.44k
    if (Value *array = FindArray(obj, "nodes")) {
1810
11.9k
        for (unsigned int i = 0; i < array->Size(); ++i) {
1811
6.72k
            if (!(*array)[i].IsUint()) continue;
1812
6.61k
            Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
1813
6.61k
            if (node)
1814
5.33k
                this->nodes.push_back(node);
1815
6.61k
        }
1816
5.26k
    }
1817
5.44k
}
1818
1819
3.96k
inline void Skin::Read(Value &obj, Asset &r) {
1820
3.96k
    if (Value *matrices = FindUInt(obj, "inverseBindMatrices")) {
1821
898
        inverseBindMatrices = r.accessors.Retrieve(matrices->GetUint());
1822
898
    }
1823
1824
3.96k
    if (Value *joints = FindArray(obj, "joints")) {
1825
6.82k
        for (unsigned i = 0; i < joints->Size(); ++i) {
1826
5.97k
            if (!(*joints)[i].IsUint()) continue;
1827
5.90k
            Ref<Node> node = r.nodes.Retrieve((*joints)[i].GetUint());
1828
5.90k
            if (node) {
1829
5.87k
                this->jointNames.push_back(node);
1830
5.87k
            }
1831
5.90k
        }
1832
852
    }
1833
3.96k
}
1834
1835
325
inline void Animation::Read(Value &obj, Asset &r) {
1836
325
    Value *curSamplers = FindArray(obj, "samplers");
1837
325
    if (nullptr != curSamplers) {
1838
490
        for (unsigned i = 0; i < curSamplers->Size(); ++i) {
1839
267
            Value &sampler = (*curSamplers)[i];
1840
1841
267
            Sampler s;
1842
267
            if (Value *input = FindUInt(sampler, "input")) {
1843
217
                s.input = r.accessors.Retrieve(input->GetUint());
1844
217
            }
1845
267
            if (Value *output = FindUInt(sampler, "output")) {
1846
173
                s.output = r.accessors.Retrieve(output->GetUint());
1847
173
            }
1848
267
            s.interpolation = Interpolation_LINEAR;
1849
267
            if (Value *interpolation = FindString(sampler, "interpolation")) {
1850
140
                const std::string interp = interpolation->GetString();
1851
140
                if (interp == "LINEAR") {
1852
119
                    s.interpolation = Interpolation_LINEAR;
1853
119
                } else if (interp == "STEP") {
1854
0
                    s.interpolation = Interpolation_STEP;
1855
21
                } else if (interp == "CUBICSPLINE") {
1856
0
                    s.interpolation = Interpolation_CUBICSPLINE;
1857
0
                }
1858
140
            }
1859
267
            this->samplers.push_back(s);
1860
267
        }
1861
223
    }
1862
1863
325
    Value *curChannels = FindArray(obj, "channels");
1864
325
    if (nullptr != curChannels) {
1865
482
        for (unsigned i = 0; i < curChannels->Size(); ++i) {
1866
247
            Value &channel = (*curChannels)[i];
1867
1868
247
            Channel c;
1869
247
            Value *curSampler = FindUInt(channel, "sampler");
1870
247
            if (nullptr != curSampler) {
1871
219
                c.sampler = curSampler->GetUint();
1872
219
            }
1873
1874
247
            if (Value *target = FindObject(channel, "target")) {
1875
182
                if (Value *node = FindUInt(*target, "node")) {
1876
145
                    c.target.node = r.nodes.Retrieve(node->GetUint());
1877
145
                }
1878
182
                if (Value *path = FindString(*target, "path")) {
1879
160
                    const std::string p = path->GetString();
1880
160
                    if (p == "translation") {
1881
0
                        c.target.path = AnimationPath_TRANSLATION;
1882
160
                    } else if (p == "rotation") {
1883
128
                        c.target.path = AnimationPath_ROTATION;
1884
128
                    } else if (p == "scale") {
1885
0
                        c.target.path = AnimationPath_SCALE;
1886
32
                    } else if (p == "weights") {
1887
7
                        c.target.path = AnimationPath_WEIGHTS;
1888
7
                    }
1889
160
                }
1890
182
            }
1891
247
            this->channels.push_back(c);
1892
247
        }
1893
235
    }
1894
325
}
1895
1896
12.5k
inline void AssetMetadata::Read(Document &doc) {
1897
12.5k
    if (Value *obj = FindObject(doc, "asset")) {
1898
11.9k
        ReadMember(*obj, "copyright", copyright);
1899
11.9k
        ReadMember(*obj, "generator", generator);
1900
1901
11.9k
        if (Value *versionString = FindStringInContext(*obj, "version", "\"asset\"")) {
1902
11.1k
            version = versionString->GetString();
1903
11.1k
        }
1904
11.9k
        Value *curProfile = FindObjectInContext(*obj, "profile", "\"asset\"");
1905
11.9k
        if (nullptr != curProfile) {
1906
58
            ReadMember(*curProfile, "api", this->profile.api);
1907
58
            ReadMember(*curProfile, "version", this->profile.version);
1908
58
        }
1909
11.9k
    }
1910
1911
12.5k
    if (version.empty() || version[0] != '2') {
1912
748
        throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
1913
748
    }
1914
12.5k
}
1915
1916
//
1917
// Asset methods implementation
1918
//
1919
1920
7.98k
inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData) {
1921
7.98k
    ASSIMP_LOG_DEBUG("Reading GLTF2 binary");
1922
7.98k
    GLB_Header header;
1923
7.98k
    if (stream.Read(&header, sizeof(header), 1) != 1) {
1924
0
        throw DeadlyImportError("GLTF: Unable to read the file header");
1925
0
    }
1926
1927
7.98k
    if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
1928
0
        throw DeadlyImportError("GLTF: Invalid binary glTF file");
1929
0
    }
1930
1931
7.98k
    AI_SWAP4(header.version);
1932
7.98k
    asset.version = ai_to_string(header.version);
1933
7.98k
    if (header.version != 2) {
1934
273
        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
1935
273
    }
1936
1937
7.71k
    GLB_Chunk chunk;
1938
7.71k
    if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
1939
0
        throw DeadlyImportError("GLTF: Unable to read JSON chunk");
1940
0
    }
1941
1942
7.71k
    AI_SWAP4(chunk.chunkLength);
1943
7.71k
    AI_SWAP4(chunk.chunkType);
1944
1945
7.71k
    if (chunk.chunkType != ChunkType_JSON) {
1946
50
        throw DeadlyImportError("GLTF: JSON chunk missing");
1947
50
    }
1948
1949
    // read the scene data, ensure null termination
1950
7.66k
    static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
1951
7.66k
    mSceneLength = chunk.chunkLength; // Can't be larger than 4GB (max. uint32_t)
1952
7.66k
    sceneData.resize(mSceneLength + 1);
1953
7.66k
    sceneData[mSceneLength] = '\0';
1954
1955
7.66k
    if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
1956
88
        throw DeadlyImportError("GLTF: Could not read the file contents");
1957
88
    }
1958
1959
7.57k
    uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
1960
7.57k
    if (padding > 0) {
1961
142
        stream.Seek(padding, aiOrigin_CUR);
1962
142
    }
1963
1964
7.57k
    AI_SWAP4(header.length);
1965
7.57k
    mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
1966
7.57k
    if (header.length >= mBodyOffset) {
1967
7.45k
        if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
1968
38
            throw DeadlyImportError("GLTF: Unable to read BIN chunk");
1969
38
        }
1970
1971
7.41k
        AI_SWAP4(chunk.chunkLength);
1972
7.41k
        AI_SWAP4(chunk.chunkType);
1973
1974
7.41k
        if (chunk.chunkType != ChunkType_BIN) {
1975
244
            throw DeadlyImportError("GLTF: BIN chunk missing");
1976
244
        }
1977
1978
7.16k
        mBodyLength = chunk.chunkLength;
1979
7.16k
    } else {
1980
122
        mBodyOffset = mBodyLength = 0;
1981
122
    }
1982
7.57k
}
1983
1984
16.0k
inline rapidjson::Document Asset::ReadDocument(IOStream &stream, bool isBinary, std::vector<char> &sceneData) {
1985
16.0k
    ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
1986
1987
    // is binary? then read the header
1988
16.0k
    if (isBinary) {
1989
7.98k
        SetAsBinary(); // also creates the body buffer
1990
7.98k
        ReadBinaryHeader(stream, sceneData);
1991
8.07k
    } else {
1992
8.07k
        mSceneLength = stream.FileSize();
1993
8.07k
        mBodyLength = 0;
1994
1995
        // Binary format only supports up to 4GB of JSON, use that as a maximum
1996
8.07k
        if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
1997
0
            throw DeadlyImportError("GLTF: JSON size greater than 4GB");
1998
0
        }
1999
2000
        // read the scene data, ensure null termination
2001
8.07k
        sceneData.resize(mSceneLength + 1);
2002
8.07k
        sceneData[mSceneLength] = '\0';
2003
2004
8.07k
        if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
2005
0
            throw DeadlyImportError("GLTF: Could not read the file contents");
2006
0
        }
2007
8.07k
    }
2008
2009
    // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
2010
16.0k
    if (mSceneLength < 2) {
2011
2
        throw DeadlyImportError("GLTF: No JSON file contents");
2012
2
    }
2013
2014
    // parse the JSON document
2015
16.0k
    ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
2016
16.0k
    Document doc;
2017
16.0k
    doc.ParseInsitu(&sceneData[0]);
2018
2019
16.0k
    if (doc.HasParseError()) {
2020
2.44k
        char buffer[32];
2021
2.44k
        ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
2022
2.44k
        throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
2023
2.44k
    }
2024
2025
13.6k
    if (!doc.IsObject()) {
2026
251
        throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
2027
251
    }
2028
2029
13.3k
    return doc;
2030
13.6k
}
2031
2032
inline void Asset::Load(const std::string &pFile, bool isBinary)
2033
5.88k
{
2034
5.88k
    mCurrentAssetDir.clear();
2035
5.88k
    if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
2036
0
        mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
2037
0
    }
2038
2039
5.88k
    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
2040
5.88k
    if (!stream) {
2041
0
        throw DeadlyImportError("GLTF: Could not open file for reading");
2042
0
    }
2043
2044
5.88k
    std::vector<char> sceneData;
2045
5.88k
    rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
2046
2047
    // If a schemaDocumentProvider is available, see if the glTF schema is present.
2048
    // If so, use it to validate the document.
2049
5.88k
    if (mSchemaDocumentProvider) {
2050
0
        if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
2051
            // The schemas are found here: https://github.com/KhronosGroup/glTF/tree/main/specification/2.0/schema
2052
0
            rapidjson::SchemaValidator validator(*gltfSchema);
2053
0
            if (!doc.Accept(validator)) {
2054
0
                rapidjson::StringBuffer pathBuffer;
2055
0
                validator.GetInvalidSchemaPointer().StringifyUriFragment(pathBuffer);
2056
0
                rapidjson::StringBuffer argumentBuffer;
2057
0
                validator.GetInvalidDocumentPointer().StringifyUriFragment(argumentBuffer);
2058
0
                throw DeadlyImportError("GLTF: The JSON document did not satisfy the glTF2 schema. Schema keyword: ", validator.GetInvalidSchemaKeyword(), ", document path: ", pathBuffer.GetString(), ", argument: ", argumentBuffer.GetString());
2059
0
            }
2060
0
        }
2061
0
    }
2062
2063
    // Fill the buffer instance for the current file embedded contents
2064
5.88k
    if (mBodyLength > 0) {
2065
3.55k
        if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
2066
30
            throw DeadlyImportError("GLTF: Unable to read gltf file");
2067
30
        }
2068
3.55k
    }
2069
2070
    // Load the metadata
2071
5.85k
    asset.Read(doc);
2072
5.85k
    ReadExtensionsUsed(doc);
2073
5.85k
    ReadExtensionsRequired(doc);
2074
2075
5.85k
#ifndef ASSIMP_ENABLE_DRACO
2076
    // Is Draco required?
2077
5.85k
    if (extensionsRequired.KHR_draco_mesh_compression) {
2078
4
        throw DeadlyImportError("GLTF: Draco mesh compression not supported.");
2079
4
    }
2080
5.85k
#endif
2081
2082
    // Prepare the dictionaries
2083
86.1k
    for (size_t i = 0; i < mDicts.size(); ++i) {
2084
80.3k
        mDicts[i]->AttachToDocument(doc);
2085
80.3k
    }
2086
2087
    // Read the "extensions" property, then add it to each scene's metadata.
2088
5.85k
    CustomExtension customExtensions;
2089
5.85k
    if (Value *extensionsObject = FindObject(doc, "extensions")) {
2090
0
        customExtensions = glTF2::ReadExtensions("extensions", *extensionsObject);
2091
0
    }
2092
2093
    // Read the "scene" property, which specifies which scene to load
2094
    // and recursively load everything referenced by it
2095
5.85k
    unsigned int sceneIndex = 0;
2096
5.85k
    Value *curScene = FindUInt(doc, "scene");
2097
5.85k
    if (nullptr != curScene) {
2098
4.20k
        sceneIndex = curScene->GetUint();
2099
4.20k
    }
2100
2101
5.85k
    if (Value *scenesArray = FindArray(doc, "scenes")) {
2102
5.51k
        if (sceneIndex < scenesArray->Size()) {
2103
5.45k
            this->scene = scenes.Retrieve(sceneIndex);
2104
2105
5.45k
            this->scene->customExtensions = customExtensions;
2106
5.45k
        }
2107
5.51k
    }
2108
2109
5.85k
    if (Value *skinsArray = FindArray(doc, "skins")) {
2110
4.95k
        for (unsigned int i = 0; i < skinsArray->Size(); ++i) {
2111
3.96k
            skins.Retrieve(i);
2112
3.96k
        }
2113
990
    }
2114
2115
5.85k
    if (Value *animsArray = FindArray(doc, "animations")) {
2116
639
        for (unsigned int i = 0; i < animsArray->Size(); ++i) {
2117
326
            animations.Retrieve(i);
2118
326
        }
2119
313
    }
2120
2121
    // Clean up
2122
65.2k
    for (size_t i = 0; i < mDicts.size(); ++i) {
2123
59.4k
        mDicts[i]->DetachFromDocument();
2124
59.4k
    }
2125
5.85k
}
2126
2127
10.1k
inline bool Asset::CanRead(const std::string &pFile, bool isBinary) {
2128
10.1k
    try {
2129
10.1k
        shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
2130
10.1k
        if (!stream) {
2131
0
            return false;
2132
0
        }
2133
10.1k
        std::vector<char> sceneData;
2134
10.1k
        rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
2135
10.1k
        asset.Read(doc);
2136
10.1k
    } catch (...) {
2137
4.28k
        return false;
2138
4.28k
    }
2139
5.88k
    return true;
2140
10.1k
}
2141
2142
7.98k
inline void Asset::SetAsBinary() {
2143
7.98k
    if (!mBodyBuffer) {
2144
7.98k
        mBodyBuffer = buffers.Create("binary_glTF");
2145
7.98k
        mBodyBuffer->MarkAsSpecial();
2146
7.98k
    }
2147
7.98k
}
2148
2149
// As required extensions are only a concept in glTF 2.0, this is here
2150
// instead of glTFCommon.h
2151
#define CHECK_REQUIRED_EXT(EXT) \
2152
66
    if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
2153
2154
5.75k
inline void Asset::ReadExtensionsRequired(Document &doc) {
2155
5.75k
    Value *extsRequired = FindArray(doc, "extensionsRequired");
2156
5.75k
    if (nullptr == extsRequired) {
2157
5.73k
        return;
2158
5.73k
    }
2159
2160
22
    std::gltf_unordered_map<std::string, bool> exts;
2161
51
    for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
2162
29
        if ((*extsRequired)[i].IsString()) {
2163
22
            exts[(*extsRequired)[i].GetString()] = true;
2164
22
        }
2165
29
    }
2166
2167
22
    CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
2168
22
    CHECK_REQUIRED_EXT(KHR_texture_basisu);
2169
22
    CHECK_REQUIRED_EXT(EXT_texture_webp);
2170
2171
22
#undef CHECK_REQUIRED_EXT
2172
22
}
2173
2174
5.76k
inline void Asset::ReadExtensionsUsed(Document &doc) {
2175
5.76k
    Value *extsUsed = FindArray(doc, "extensionsUsed");
2176
5.76k
    if (!extsUsed) return;
2177
2178
1.02k
    std::gltf_unordered_map<std::string, bool> exts;
2179
2180
7.46k
    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
2181
6.43k
        if ((*extsUsed)[i].IsString()) {
2182
6.42k
            exts[(*extsUsed)[i].GetString()] = true;
2183
6.42k
        }
2184
6.43k
    }
2185
2186
1.02k
    CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
2187
1.02k
    CHECK_EXT(KHR_materials_specular);
2188
1.02k
    CHECK_EXT(KHR_materials_unlit);
2189
1.02k
    CHECK_EXT(KHR_lights_punctual);
2190
1.02k
    CHECK_EXT(KHR_texture_transform);
2191
1.02k
    CHECK_EXT(KHR_materials_sheen);
2192
1.02k
    CHECK_EXT(KHR_materials_clearcoat);
2193
1.02k
    CHECK_EXT(KHR_materials_transmission);
2194
1.02k
    CHECK_EXT(KHR_materials_volume);
2195
1.02k
    CHECK_EXT(KHR_materials_ior);
2196
1.02k
    CHECK_EXT(KHR_materials_emissive_strength);
2197
1.02k
    CHECK_EXT(KHR_materials_anisotropy);
2198
1.02k
    CHECK_EXT(KHR_draco_mesh_compression);
2199
1.02k
    CHECK_EXT(KHR_texture_basisu);
2200
1.02k
    CHECK_EXT(EXT_texture_webp);
2201
2202
1.02k
#undef CHECK_EXT
2203
1.02k
}
2204
2205
16.3k
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool /*absolute*/) {
2206
16.3k
#ifdef ASSIMP_API
2207
16.3k
    return mIOSystem->Open(path, mode);
2208
#else
2209
    if (path.size() < 2) return nullptr;
2210
    if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
2211
        path = mCurrentAssetDir + path;
2212
    }
2213
    FILE *f = fopen(path.c_str(), mode);
2214
    return f ? new IOStream(f) : nullptr;
2215
#endif
2216
16.3k
}
2217
2218
0
inline std::string Asset::FindUniqueID(const std::string &str, const char *suffix) {
2219
0
    std::string id = str;
2220
0
    int n = 1;
2221
0
    if(!id.empty()) {
2222
0
        n = lastUsedID[id];
2223
0
        if(!n) {
2224
0
            lastUsedID[id] = n+1;
2225
0
            return id;
2226
0
        }
2227
0
        id += "_";
2228
0
    }
2229
0
2230
0
    if(suffix) {
2231
0
        id += suffix;
2232
0
        n = lastUsedID[id];
2233
0
        if(!n) {
2234
0
            lastUsedID[id] = n+1;
2235
0
            return id;
2236
0
        }
2237
0
    }
2238
0
2239
0
    lastUsedID[id] = n+1;
2240
0
    return id + "_" + std::to_string(n-1);
2241
0
}
2242
2243
#if _MSC_VER
2244
#   pragma warning(pop)
2245
#endif // _MSC_VER
2246
2247
} // namespace glTF2