Coverage Report

Created: 2026-01-25 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/glTF2/glTF2AssetWriter.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 <assimp/Base64.hpp>
43
#include <rapidjson/stringbuffer.h>
44
#include <rapidjson/writer.h>
45
#include <rapidjson/prettywriter.h>
46
47
namespace glTF2 {
48
49
    using rapidjson::StringBuffer;
50
    using rapidjson::PrettyWriter;
51
    using rapidjson::Writer;
52
    using rapidjson::StringRef;
53
    using rapidjson::StringRef;
54
55
    namespace {
56
57
        template<typename T, size_t N>
58
0
        inline Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) {
59
0
            val.SetArray();
60
0
            val.Reserve(N, al);
61
0
            for (decltype(N) i = 0; i < N; ++i) {
62
0
                val.PushBack(r[i], al);
63
0
            }
64
0
            return val;
65
0
        }
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
66
67
        template<typename T>
68
0
        inline Value& MakeValue(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
69
0
            val.SetArray();
70
0
            val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
71
0
            for (unsigned int i = 0; i < r.size(); ++i) {
72
0
                val.PushBack(r[i], al);
73
0
            }
74
0
            return val;
75
0
        }
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
76
77
        template<typename C, typename T>
78
0
        inline Value& MakeValueCast(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
79
0
            val.SetArray();
80
0
            val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
81
0
            for (unsigned int i = 0; i < r.size(); ++i) {
82
0
                val.PushBack(static_cast<C>(r[i]), al);
83
0
            }
84
0
            return val;
85
0
        }
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValueCast<long, double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValueCast<long, double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
86
87
        template<typename T>
88
0
        inline Value& MakeValue(Value& val, T r, MemoryPoolAllocator<>& /*al*/) {
89
0
            val.Set(r);
90
91
0
            return val;
92
0
        }
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<char const*>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, double, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<unsigned long>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, unsigned long, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<long>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, long, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<bool>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, bool, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<float>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<char const*>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, double, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<unsigned long>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, unsigned long, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<long>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, long, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF2::(anonymous namespace)::MakeValue<bool>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, bool, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
93
94
        template<class T>
95
0
        inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
96
0
            if (v.empty()) return;
97
0
            Value lst;
98
0
            lst.SetArray();
99
0
            lst.Reserve(unsigned(v.size()), al);
100
0
            for (size_t i = 0; i < v.size(); ++i) {
101
0
                lst.PushBack(v[i]->index, al);
102
0
            }
103
0
            obj.AddMember(StringRef(fieldId), lst, al);
104
0
        }
Unexecuted instantiation: glTF2Importer.cpp:void glTF2::(anonymous namespace)::AddRefsVector<glTF2::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Node>, std::__1::allocator<glTFCommon::Ref<glTF2::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:void glTF2::(anonymous namespace)::AddRefsVector<glTF2::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF2::Node>, std::__1::allocator<glTFCommon::Ref<glTF2::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
105
106
107
    }
108
109
    inline void Write(Value& obj, Accessor& a, AssetWriter& w)
110
0
    {
111
0
        if (a.bufferView) {
112
0
            obj.AddMember("bufferView", a.bufferView->index, w.mAl);
113
0
            obj.AddMember("byteOffset", (unsigned int)a.byteOffset, w.mAl);
114
0
        }
115
0
        obj.AddMember("componentType", int(a.componentType), w.mAl);
116
0
        obj.AddMember("count", (unsigned int)a.count, w.mAl);
117
0
        obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
118
0
        Value vTmpMax, vTmpMin;
119
0
        if (a.componentType == ComponentType_FLOAT) {
120
0
            obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
121
0
            obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
122
0
        } else {
123
0
            obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
124
0
            obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
125
0
        }
126
127
0
        if (a.sparse) {
128
0
            Value sparseValue;
129
0
            sparseValue.SetObject();
130
131
            //count
132
0
            sparseValue.AddMember("count", (unsigned int)a.sparse->count, w.mAl);
133
134
            //indices
135
0
            Value indices;
136
0
            indices.SetObject();
137
0
            indices.AddMember("bufferView", a.sparse->indices->index, w.mAl);
138
0
            indices.AddMember("byteOffset", (unsigned int)a.sparse->indicesByteOffset, w.mAl);
139
0
            indices.AddMember("componentType", int(a.sparse->indicesType), w.mAl);
140
0
            sparseValue.AddMember("indices", indices, w.mAl);
141
142
            //values
143
0
            Value values;
144
0
            values.SetObject();
145
0
            values.AddMember("bufferView", a.sparse->values->index, w.mAl);
146
0
            values.AddMember("byteOffset", (unsigned int)a.sparse->valuesByteOffset, w.mAl);
147
0
            sparseValue.AddMember("values", values, w.mAl);
148
149
0
            obj.AddMember("sparse", sparseValue, w.mAl);
150
0
        }
151
0
    }
152
153
    inline void Write(Value& obj, Animation& a, AssetWriter& w)
154
0
    {
155
        /****************** Channels *******************/
156
0
        Value channels;
157
0
        channels.SetArray();
158
0
        channels.Reserve(unsigned(a.channels.size()), w.mAl);
159
160
0
        for (size_t i = 0; i < unsigned(a.channels.size()); ++i) {
161
0
            Animation::Channel& c = a.channels[i];
162
0
            Value valChannel;
163
0
            valChannel.SetObject();
164
0
            {
165
0
                valChannel.AddMember("sampler", c.sampler, w.mAl);
166
167
0
                Value valTarget;
168
0
                valTarget.SetObject();
169
0
                {
170
0
                    valTarget.AddMember("node", c.target.node->index, w.mAl);
171
0
                    switch (c.target.path) {
172
0
                        case AnimationPath_TRANSLATION:
173
0
                            valTarget.AddMember("path", "translation", w.mAl);
174
0
                            break;
175
0
                        case AnimationPath_ROTATION:
176
0
                            valTarget.AddMember("path", "rotation", w.mAl);
177
0
                            break;
178
0
                        case AnimationPath_SCALE:
179
0
                            valTarget.AddMember("path", "scale", w.mAl);
180
0
                            break;
181
0
                        case AnimationPath_WEIGHTS:
182
0
                            valTarget.AddMember("path", "weights", w.mAl);
183
0
                            break;
184
0
                    }
185
0
                }
186
0
                valChannel.AddMember("target", valTarget, w.mAl);
187
0
            }
188
0
            channels.PushBack(valChannel, w.mAl);
189
0
        }
190
0
        obj.AddMember("channels", channels, w.mAl);
191
192
        /****************** Samplers *******************/
193
0
        Value valSamplers;
194
0
        valSamplers.SetArray();
195
196
0
        for (size_t i = 0; i < unsigned(a.samplers.size()); ++i) {
197
0
            Animation::Sampler& s = a.samplers[i];
198
0
            Value valSampler;
199
0
            valSampler.SetObject();
200
0
            {
201
0
                valSampler.AddMember("input", s.input->index, w.mAl);
202
0
                switch (s.interpolation) {
203
0
                    case Interpolation_LINEAR:
204
0
                        valSampler.AddMember("interpolation", "LINEAR", w.mAl);
205
0
                        break;
206
0
                    case Interpolation_STEP:
207
0
                        valSampler.AddMember("interpolation", "STEP", w.mAl);
208
0
                        break;
209
0
                    case Interpolation_CUBICSPLINE:
210
0
                        valSampler.AddMember("interpolation", "CUBICSPLINE", w.mAl);
211
0
                        break;
212
0
                }
213
0
                valSampler.AddMember("output", s.output->index, w.mAl);
214
0
            }
215
0
            valSamplers.PushBack(valSampler, w.mAl);
216
0
        }
217
0
        obj.AddMember("samplers", valSamplers, w.mAl);
218
0
    }
219
220
    inline void Write(Value& obj, Buffer& b, AssetWriter& w)
221
0
    {
222
0
        obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
223
224
0
        const auto uri = b.GetURI();
225
0
        const auto relativeUri = uri.substr(uri.find_last_of("/\\") + 1u);
226
0
        obj.AddMember("uri", Value(relativeUri, w.mAl).Move(), w.mAl);
227
0
    }
228
229
    inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
230
0
    {
231
0
        obj.AddMember("buffer", bv.buffer->index, w.mAl);
232
0
        obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
233
0
        obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
234
0
        if (bv.byteStride != 0) {
235
0
            obj.AddMember("byteStride", bv.byteStride, w.mAl);
236
0
        }
237
0
        if (bv.target != BufferViewTarget_NONE) {
238
0
            obj.AddMember("target", int(bv.target), w.mAl);
239
0
        }
240
0
    }
241
242
    inline void Write(Value& /*obj*/, Camera& /*c*/, AssetWriter& /*w*/)
243
0
    {
244
245
0
    }
246
247
    inline void Write(Value& /*obj*/, Light& /*c*/, AssetWriter& /*w*/)
248
0
    {
249
250
0
    }
251
252
    inline void Write(Value& obj, Image& img, AssetWriter& w)
253
0
    {
254
        //basisu: no need to handle .ktx2, .basis, write as is
255
0
        if (img.bufferView) {
256
0
            obj.AddMember("bufferView", img.bufferView->index, w.mAl);
257
0
            obj.AddMember("mimeType", Value(img.mimeType, w.mAl).Move(), w.mAl);
258
0
        }
259
0
        else {
260
0
            std::string uri;
261
0
            if (img.HasData()) {
262
0
                uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
263
0
                uri += ";base64,";
264
0
                Base64::Encode(img.GetData(), img.GetDataLength(), uri);
265
0
            }
266
0
            else {
267
0
                uri = img.uri;
268
0
            }
269
270
0
            obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl);
271
0
        }
272
0
    }
273
274
    namespace {
275
        inline void SetTexBasic(TextureInfo t, Value& tex, MemoryPoolAllocator<>& al)
276
0
        {
277
0
            tex.SetObject();
278
0
            tex.AddMember("index", t.texture->index, al);
279
280
0
            if (t.texCoord != 0) {
281
0
                tex.AddMember("texCoord", t.texCoord, al);
282
0
            }
283
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::SetTexBasic(glTF2::TextureInfo, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::SetTexBasic(glTF2::TextureInfo, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
284
285
        inline void WriteTex(Value& obj, TextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
286
0
        {
287
288
0
            if (t.texture) {
289
0
                Value tex;
290
291
0
                SetTexBasic(t, tex, al);
292
293
0
                obj.AddMember(StringRef(propName), tex, al);
294
0
            }
295
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::TextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::TextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
296
297
        inline void WriteTex(Value& obj, NormalTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
298
0
        {
299
300
0
            if (t.texture) {
301
0
                Value tex;
302
303
0
                SetTexBasic(t, tex, al);
304
305
0
                if (t.scale != 1) {
306
0
                    tex.AddMember("scale", t.scale, al);
307
0
                }
308
309
0
                obj.AddMember(StringRef(propName), tex, al);
310
0
            }
311
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::NormalTextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::NormalTextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
312
313
        inline void WriteTex(Value& obj, OcclusionTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
314
0
        {
315
316
0
            if (t.texture) {
317
0
                Value tex;
318
319
0
                SetTexBasic(t, tex, al);
320
321
0
                if (t.strength != 1) {
322
0
                    tex.AddMember("strength", t.strength, al);
323
0
                }
324
325
0
                obj.AddMember(StringRef(propName), tex, al);
326
0
            }
327
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::OcclusionTextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::WriteTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF2::OcclusionTextureInfo, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
328
329
        template<size_t N>
330
        inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, MemoryPoolAllocator<>& al)
331
0
        {
332
0
            Value arr;
333
0
            obj.AddMember(StringRef(propName), MakeValue(arr, prop, al), al);
334
0
        }
Unexecuted instantiation: glTF2Importer.cpp:void glTF2::(anonymous namespace)::WriteVec<4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:void glTF2::(anonymous namespace)::WriteVec<3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:void glTF2::(anonymous namespace)::WriteVec<4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:void glTF2::(anonymous namespace)::WriteVec<3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
335
336
        template<size_t N>
337
        inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, const float(&defaultVal)[N], MemoryPoolAllocator<>& al)
338
0
        {
339
0
            if (!std::equal(std::begin(prop), std::end(prop), std::begin(defaultVal))) {
340
0
                WriteVec(obj, prop, propName, al);
341
0
            }
342
0
        }
Unexecuted instantiation: glTF2Importer.cpp:void glTF2::(anonymous namespace)::WriteVec<4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], char const*, float const (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Importer.cpp:void glTF2::(anonymous namespace)::WriteVec<3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], char const*, float const (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:void glTF2::(anonymous namespace)::WriteVec<4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], char const*, float const (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:void glTF2::(anonymous namespace)::WriteVec<3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], char const*, float const (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
343
344
        inline void WriteFloat(Value& obj, float prop, const char* propName, MemoryPoolAllocator<>& al)
345
0
        {
346
0
            Value num;
347
0
            obj.AddMember(StringRef(propName), MakeValue(num, prop, al), al);
348
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::WriteFloat(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::WriteFloat(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
349
    }
350
351
    inline void Write(Value& obj, Material& m, AssetWriter& w)
352
0
    {
353
0
        Value pbrMetallicRoughness;
354
0
        pbrMetallicRoughness.SetObject();
355
0
        {
356
0
            WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorTexture, "baseColorTexture", w.mAl);
357
0
            WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicRoughnessTexture, "metallicRoughnessTexture", w.mAl);
358
0
            WriteVec(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorFactor, "baseColorFactor", defaultBaseColor, w.mAl);
359
360
0
            if (m.pbrMetallicRoughness.metallicFactor != 1) {
361
0
                WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicFactor, "metallicFactor", w.mAl);
362
0
            }
363
364
0
            if (m.pbrMetallicRoughness.roughnessFactor != 1) {
365
0
                WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.roughnessFactor, "roughnessFactor", w.mAl);
366
0
            }
367
0
        }
368
369
0
        if (!pbrMetallicRoughness.ObjectEmpty()) {
370
0
            obj.AddMember("pbrMetallicRoughness", pbrMetallicRoughness, w.mAl);
371
0
        }
372
373
0
        WriteTex(obj, m.normalTexture, "normalTexture", w.mAl);
374
0
        WriteTex(obj, m.emissiveTexture, "emissiveTexture", w.mAl);
375
0
        WriteTex(obj, m.occlusionTexture, "occlusionTexture", w.mAl);
376
0
        WriteVec(obj, m.emissiveFactor, "emissiveFactor", defaultEmissiveFactor, w.mAl);
377
378
0
        if (m.alphaCutoff != 0.5) {
379
0
            WriteFloat(obj, m.alphaCutoff, "alphaCutoff", w.mAl);
380
0
        }
381
382
0
        if (m.alphaMode != "OPAQUE") {
383
0
            obj.AddMember("alphaMode", Value(m.alphaMode, w.mAl).Move(), w.mAl);
384
0
        }
385
386
0
        if (m.doubleSided) {
387
0
            obj.AddMember("doubleSided", m.doubleSided, w.mAl);
388
0
        }
389
390
0
        Value exts;
391
0
        exts.SetObject();
392
393
0
        if (m.pbrSpecularGlossiness.isPresent) {
394
0
            Value pbrSpecularGlossiness;
395
0
            pbrSpecularGlossiness.SetObject();
396
397
0
            PbrSpecularGlossiness &pbrSG = m.pbrSpecularGlossiness.value;
398
399
            //pbrSpecularGlossiness
400
0
            WriteVec(pbrSpecularGlossiness, pbrSG.diffuseFactor, "diffuseFactor", defaultDiffuseFactor, w.mAl);
401
0
            WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
402
403
0
            if (pbrSG.glossinessFactor != 1) {
404
0
                WriteFloat(pbrSpecularGlossiness, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
405
0
            }
406
407
0
            WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
408
0
            WriteTex(pbrSpecularGlossiness, pbrSG.specularGlossinessTexture, "specularGlossinessTexture", w.mAl);
409
410
0
            if (!pbrSpecularGlossiness.ObjectEmpty()) {
411
0
                exts.AddMember("KHR_materials_pbrSpecularGlossiness", pbrSpecularGlossiness, w.mAl);
412
0
            }
413
0
        }
414
415
0
        if (m.unlit) {
416
0
          Value unlit;
417
0
          unlit.SetObject();
418
0
          exts.AddMember("KHR_materials_unlit", unlit, w.mAl);
419
0
        }
420
421
0
        if (m.materialSpecular.isPresent) {
422
0
            Value materialSpecular(rapidjson::Type::kObjectType);
423
0
            materialSpecular.SetObject();
424
425
0
            MaterialSpecular &specular = m.materialSpecular.value;
426
427
0
            if (specular.specularFactor != 0.0f) {
428
0
                WriteFloat(materialSpecular, specular.specularFactor, "specularFactor", w.mAl);
429
0
            }
430
0
            if (specular.specularColorFactor[0] != defaultSpecularColorFactor[0] && specular.specularColorFactor[1] != defaultSpecularColorFactor[1] && specular.specularColorFactor[2] != defaultSpecularColorFactor[2]) {
431
0
                WriteVec(materialSpecular, specular.specularColorFactor, "specularColorFactor", w.mAl);
432
0
            }
433
434
0
            WriteTex(materialSpecular, specular.specularTexture, "specularTexture", w.mAl);
435
0
            WriteTex(materialSpecular, specular.specularColorTexture, "specularColorTexture", w.mAl);
436
437
0
            if (!materialSpecular.ObjectEmpty()) {
438
0
                exts.AddMember("KHR_materials_specular", materialSpecular, w.mAl);
439
0
            }
440
0
        }
441
442
0
        if (m.materialSheen.isPresent) {
443
0
            Value materialSheen(rapidjson::Type::kObjectType);
444
445
0
            MaterialSheen &sheen = m.materialSheen.value;
446
447
0
            WriteVec(materialSheen, sheen.sheenColorFactor, "sheenColorFactor", defaultSheenFactor, w.mAl);
448
449
0
            if (sheen.sheenRoughnessFactor != 0.f) {
450
0
                WriteFloat(materialSheen, sheen.sheenRoughnessFactor, "sheenRoughnessFactor", w.mAl);
451
0
            }
452
453
0
            WriteTex(materialSheen, sheen.sheenColorTexture, "sheenColorTexture", w.mAl);
454
0
            WriteTex(materialSheen, sheen.sheenRoughnessTexture, "sheenRoughnessTexture", w.mAl);
455
456
0
            if (!materialSheen.ObjectEmpty()) {
457
0
                exts.AddMember("KHR_materials_sheen", materialSheen, w.mAl);
458
0
            }
459
0
        }
460
461
0
        if (m.materialClearcoat.isPresent) {
462
0
            Value materialClearcoat(rapidjson::Type::kObjectType);
463
464
0
            MaterialClearcoat &clearcoat = m.materialClearcoat.value;
465
466
0
            if (clearcoat.clearcoatFactor != 0.f) {
467
0
                WriteFloat(materialClearcoat, clearcoat.clearcoatFactor, "clearcoatFactor", w.mAl);
468
0
            }
469
470
0
            if (clearcoat.clearcoatRoughnessFactor != 0.f) {
471
0
                WriteFloat(materialClearcoat, clearcoat.clearcoatRoughnessFactor, "clearcoatRoughnessFactor", w.mAl);
472
0
            }
473
474
0
            WriteTex(materialClearcoat, clearcoat.clearcoatTexture, "clearcoatTexture", w.mAl);
475
0
            WriteTex(materialClearcoat, clearcoat.clearcoatRoughnessTexture, "clearcoatRoughnessTexture", w.mAl);
476
0
            WriteTex(materialClearcoat, clearcoat.clearcoatNormalTexture, "clearcoatNormalTexture", w.mAl);
477
478
0
            if (!materialClearcoat.ObjectEmpty()) {
479
0
                exts.AddMember("KHR_materials_clearcoat", materialClearcoat, w.mAl);
480
0
            }
481
0
        }
482
483
0
        if (m.materialTransmission.isPresent) {
484
0
            Value materialTransmission(rapidjson::Type::kObjectType);
485
486
0
            MaterialTransmission &transmission = m.materialTransmission.value;
487
488
0
            if (transmission.transmissionFactor != 0.f) {
489
0
                WriteFloat(materialTransmission, transmission.transmissionFactor, "transmissionFactor", w.mAl);
490
0
            }
491
492
0
            WriteTex(materialTransmission, transmission.transmissionTexture, "transmissionTexture", w.mAl);
493
494
0
            if (!materialTransmission.ObjectEmpty()) {
495
0
                exts.AddMember("KHR_materials_transmission", materialTransmission, w.mAl);
496
0
            }
497
0
        }
498
499
0
        if (m.materialVolume.isPresent) {
500
0
            Value materialVolume(rapidjson::Type::kObjectType);
501
502
0
            MaterialVolume &volume = m.materialVolume.value;
503
504
0
            if (volume.thicknessFactor != 0.f) {
505
0
                WriteFloat(materialVolume, volume.thicknessFactor, "thicknessFactor", w.mAl);
506
0
            }
507
508
0
            WriteTex(materialVolume, volume.thicknessTexture, "thicknessTexture", w.mAl);
509
510
0
            if (volume.attenuationDistance != std::numeric_limits<float>::infinity()) {
511
0
                WriteFloat(materialVolume, volume.attenuationDistance, "attenuationDistance", w.mAl);
512
0
            }
513
514
0
            WriteVec(materialVolume, volume.attenuationColor, "attenuationColor", defaultAttenuationColor, w.mAl);
515
516
0
            if (!materialVolume.ObjectEmpty()) {
517
0
                exts.AddMember("KHR_materials_volume", materialVolume, w.mAl);
518
0
            }
519
0
        }
520
521
0
        if (m.materialIOR.isPresent) {
522
0
            Value materialIOR(rapidjson::Type::kObjectType);
523
524
0
            MaterialIOR &ior = m.materialIOR.value;
525
526
0
            if (ior.ior != 1.5f) {
527
0
                WriteFloat(materialIOR, ior.ior, "ior", w.mAl);
528
0
            }
529
530
0
            if (!materialIOR.ObjectEmpty()) {
531
0
                exts.AddMember("KHR_materials_ior", materialIOR, w.mAl);
532
0
            }
533
0
        }
534
535
0
        if (m.materialEmissiveStrength.isPresent) {
536
0
            Value materialEmissiveStrength(rapidjson::Type::kObjectType);
537
538
0
            MaterialEmissiveStrength &emissiveStrength = m.materialEmissiveStrength.value;
539
540
0
            if (emissiveStrength.emissiveStrength != 0.f) {
541
0
                WriteFloat(materialEmissiveStrength, emissiveStrength.emissiveStrength, "emissiveStrength", w.mAl);
542
0
            }
543
544
0
            if (!materialEmissiveStrength.ObjectEmpty()) {
545
0
                exts.AddMember("KHR_materials_emissive_strength", materialEmissiveStrength, w.mAl);
546
0
            }
547
0
        }
548
549
0
        if (m.materialAnisotropy.isPresent) {
550
0
            Value materialAnisotropy(rapidjson::Type::kObjectType);
551
552
0
            MaterialAnisotropy &anisotropy = m.materialAnisotropy.value;
553
554
0
            if (anisotropy.anisotropyStrength != 0.f) {
555
0
                WriteFloat(materialAnisotropy, anisotropy.anisotropyStrength, "anisotropyStrength", w.mAl);
556
0
            }
557
558
0
            if (anisotropy.anisotropyRotation != 0.f) {
559
0
                WriteFloat(materialAnisotropy, anisotropy.anisotropyRotation, "anisotropyRotation", w.mAl);
560
0
            }
561
562
0
            WriteTex(materialAnisotropy, anisotropy.anisotropyTexture, "anisotropyTexture", w.mAl);
563
564
0
            if (!materialAnisotropy.ObjectEmpty()) {
565
0
                exts.AddMember("KHR_materials_anisotropy", materialAnisotropy, w.mAl);
566
0
            }
567
0
        }
568
569
0
        if (!exts.ObjectEmpty()) {
570
0
            obj.AddMember("extensions", exts, w.mAl);
571
0
        }
572
0
    }
573
574
    namespace {
575
        inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst,
576
            const char* semantic, bool forceNumber = false)
577
0
        {
578
0
            if (lst.empty()) return;
579
0
            if (lst.size() == 1 && !forceNumber) {
580
0
                attrs.AddMember(StringRef(semantic), lst[0]->index, w.mAl);
581
0
            }
582
0
            else {
583
0
                for (size_t i = 0; i < lst.size(); ++i) {
584
0
                    char buffer[32];
585
0
                    ai_snprintf(buffer, 32, "%s_%d", semantic, int(i));
586
0
                    attrs.AddMember(Value(buffer, w.mAl).Move(), lst[i]->index, w.mAl);
587
0
                }
588
0
            }
589
0
        }
Unexecuted instantiation: glTF2Importer.cpp:glTF2::(anonymous namespace)::WriteAttrs(glTF2::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >&, char const*, bool)
Unexecuted instantiation: glTF2Exporter.cpp:glTF2::(anonymous namespace)::WriteAttrs(glTF2::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF2::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF2::Accessor> > >&, char const*, bool)
590
    }
591
592
    inline void Write(Value& obj, Mesh& m, AssetWriter& w)
593
0
    {
594
        /****************** Primitives *******************/
595
0
        Value primitives;
596
0
        primitives.SetArray();
597
0
        primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
598
599
0
        for (size_t i = 0; i < m.primitives.size(); ++i) {
600
0
            Mesh::Primitive& p = m.primitives[i];
601
0
            Value prim;
602
0
            prim.SetObject();
603
604
            // Extensions
605
0
            if (p.ngonEncoded)
606
0
            {
607
0
                Value exts;
608
0
                exts.SetObject();
609
610
0
                Value FB_ngon_encoding;
611
0
                FB_ngon_encoding.SetObject();
612
613
0
                exts.AddMember(StringRef("FB_ngon_encoding"), FB_ngon_encoding, w.mAl);
614
0
                prim.AddMember("extensions", exts, w.mAl);
615
0
            }
616
617
0
            {
618
0
                prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
619
620
0
                if (p.material)
621
0
                    prim.AddMember("material", p.material->index, w.mAl);
622
623
0
                if (p.indices)
624
0
                    prim.AddMember("indices", p.indices->index, w.mAl);
625
626
0
                Value attrs;
627
0
                attrs.SetObject();
628
0
                {
629
0
                    WriteAttrs(w, attrs, p.attributes.position, "POSITION");
630
0
                    WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
631
0
                    WriteAttrs(w, attrs, p.attributes.tangent, "TANGENT");
632
0
                    WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
633
0
                    WriteAttrs(w, attrs, p.attributes.color, "COLOR", true);
634
0
                    WriteAttrs(w, attrs, p.attributes.joint, "JOINTS", true);
635
0
                    WriteAttrs(w, attrs, p.attributes.weight, "WEIGHTS", true);
636
0
                }
637
0
                prim.AddMember("attributes", attrs, w.mAl);
638
639
                // targets for blendshapes
640
0
                if (p.targets.size() > 0) {
641
0
                    Value tjs;
642
0
                    tjs.SetArray();
643
0
                    tjs.Reserve(unsigned(p.targets.size()), w.mAl);
644
0
                    for (unsigned int t = 0; t < p.targets.size(); ++t) {
645
0
                        Value tj;
646
0
                        tj.SetObject();
647
0
                        {
648
0
                            WriteAttrs(w, tj, p.targets[t].position, "POSITION");
649
0
                            WriteAttrs(w, tj, p.targets[t].normal, "NORMAL");
650
0
                            WriteAttrs(w, tj, p.targets[t].tangent, "TANGENT");
651
0
                        }
652
0
                        tjs.PushBack(tj, w.mAl);
653
0
                    }
654
0
                    prim.AddMember("targets", tjs, w.mAl);
655
0
                }
656
0
            }
657
0
            primitives.PushBack(prim, w.mAl);
658
0
        }
659
660
0
        obj.AddMember("primitives", primitives, w.mAl);
661
        // targetNames
662
0
        if (m.targetNames.size() > 0) {
663
0
            Value extras;
664
0
            extras.SetObject();
665
0
            Value targetNames;
666
0
            targetNames.SetArray();
667
0
            targetNames.Reserve(unsigned(m.targetNames.size()), w.mAl);
668
0
            for (unsigned int n = 0; n < m.targetNames.size(); ++n) {
669
0
                std::string name = m.targetNames[n];
670
0
                Value tname;
671
0
                tname.SetString(name.c_str(), w.mAl);
672
0
                targetNames.PushBack(tname, w.mAl);
673
0
            }
674
0
            extras.AddMember("targetNames", targetNames, w.mAl);
675
0
            obj.AddMember("extras", extras, w.mAl);
676
0
        }
677
0
    }
678
679
0
    inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) {
680
0
        Value valueNode;
681
682
0
        if (value.mStringValue.isPresent) {
683
0
            MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl);
684
0
        } else if (value.mDoubleValue.isPresent) {
685
0
            MakeValue(valueNode, value.mDoubleValue.value, w.mAl);
686
0
        } else if (value.mUint64Value.isPresent) {
687
0
            MakeValue(valueNode, value.mUint64Value.value, w.mAl);
688
0
        } else if (value.mInt64Value.isPresent) {
689
0
            MakeValue(valueNode, value.mInt64Value.value, w.mAl);
690
0
        } else if (value.mBoolValue.isPresent) {
691
0
            MakeValue(valueNode, value.mBoolValue.value, w.mAl);
692
0
        } else if (value.mValues.isPresent) {
693
0
            valueNode.SetObject();
694
0
            for (auto const &subvalue : value.mValues.value) {
695
0
                WriteExtrasValue(valueNode, subvalue, w);
696
0
            }
697
0
        }
698
699
0
        parent.AddMember(StringRef(value.name), valueNode, w.mAl);
700
0
    }
701
702
0
    inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) {
703
0
        if (!extras.HasExtras()) {
704
0
            return;
705
0
        }
706
707
0
        Value extrasNode;
708
0
        extrasNode.SetObject();
709
710
0
        for (auto const &value : extras.mValues) {
711
0
            WriteExtrasValue(extrasNode, value, w);
712
0
        }
713
714
0
        obj.AddMember("extras", extrasNode, w.mAl);
715
0
    }
716
717
    inline void Write(Value& obj, Node& n, AssetWriter& w)
718
0
    {
719
0
        if (n.matrix.isPresent) {
720
0
            Value val;
721
0
            obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
722
0
        }
723
724
0
        if (n.translation.isPresent) {
725
0
            Value val;
726
0
            obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl);
727
0
        }
728
729
0
        if (n.scale.isPresent) {
730
0
            Value val;
731
0
            obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl);
732
0
        }
733
0
        if (n.rotation.isPresent) {
734
0
            Value val;
735
0
            obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl);
736
0
        }
737
738
0
        AddRefsVector(obj, "children", n.children, w.mAl);
739
740
0
        if (!n.meshes.empty()) {
741
0
            obj.AddMember("mesh", n.meshes[0]->index, w.mAl);
742
0
        }
743
744
0
        if (n.skin) {
745
0
            obj.AddMember("skin", n.skin->index, w.mAl);
746
0
        }
747
748
        //gltf2 spec does not support "skeletons" under node
749
0
        if(n.skeletons.size()) {
750
0
            AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
751
0
        }
752
753
0
        WriteExtras(obj, n.extras, w);
754
0
    }
755
756
    inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
757
0
    {
758
0
759
0
    }
760
761
    inline void Write(Value& obj, Sampler& b, AssetWriter& w)
762
0
    {
763
0
        if (!b.name.empty()) {
764
0
            obj.AddMember("name", b.name, w.mAl);
765
0
        }
766
767
0
        if (b.wrapS != SamplerWrap::UNSET && b.wrapS != SamplerWrap::Repeat) {
768
0
            obj.AddMember("wrapS", static_cast<unsigned int>(b.wrapS), w.mAl);
769
0
        }
770
771
0
        if (b.wrapT != SamplerWrap::UNSET && b.wrapT != SamplerWrap::Repeat) {
772
0
            obj.AddMember("wrapT", static_cast<unsigned int>(b.wrapT), w.mAl);
773
0
        }
774
775
0
        if (b.magFilter != SamplerMagFilter::UNSET) {
776
0
            obj.AddMember("magFilter", static_cast<unsigned int>(b.magFilter), w.mAl);
777
0
        }
778
779
0
        if (b.minFilter != SamplerMinFilter::UNSET) {
780
0
            obj.AddMember("minFilter", static_cast<unsigned int>(b.minFilter), w.mAl);
781
0
        }
782
0
    }
783
784
    inline void Write(Value& scene, Scene& s, AssetWriter& w)
785
0
    {
786
0
        AddRefsVector(scene, "nodes", s.nodes, w.mAl);
787
0
    }
788
789
    inline void Write(Value& /*obj*/, Shader& /*b*/, AssetWriter& /*w*/)
790
0
    {
791
0
792
0
    }
793
794
    inline void Write(Value& obj, Skin& b, AssetWriter& w)
795
0
    {
796
        /****************** jointNames *******************/
797
0
        Value vJointNames;
798
0
        vJointNames.SetArray();
799
0
        vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
800
801
0
        for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
802
0
            vJointNames.PushBack(b.jointNames[i]->index, w.mAl);
803
0
        }
804
0
        obj.AddMember("joints", vJointNames, w.mAl);
805
806
0
        if (b.bindShapeMatrix.isPresent) {
807
0
            Value val;
808
0
            obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl);
809
0
        }
810
811
0
        if (b.inverseBindMatrices) {
812
0
            obj.AddMember("inverseBindMatrices", b.inverseBindMatrices->index, w.mAl);
813
0
        }
814
815
0
    }
816
817
    inline void Write(Value& obj, Texture& tex, AssetWriter& w)
818
0
    {
819
0
        if (tex.source) {
820
0
            obj.AddMember("source", tex.source->index, w.mAl);
821
0
        }
822
0
        if (tex.sampler) {
823
0
            obj.AddMember("sampler", tex.sampler->index, w.mAl);
824
0
        }
825
0
    }
826
827
    inline AssetWriter::AssetWriter(Asset& a)
828
0
        : mDoc()
829
0
        , mAsset(a)
830
0
        , mAl(mDoc.GetAllocator())
831
0
    {
832
0
        mDoc.SetObject();
833
834
0
        WriteMetadata();
835
0
        WriteExtensionsUsed();
836
837
        // Dump the contents of the dictionaries
838
0
        for (size_t i = 0; i < a.mDicts.size(); ++i) {
839
0
            a.mDicts[i]->WriteObjects(*this);
840
0
        }
841
842
        // Add the target scene field
843
0
        if (mAsset.scene) {
844
0
            mDoc.AddMember("scene", mAsset.scene->index, mAl);
845
0
        }
846
847
0
        if(mAsset.extras) {
848
0
            mDoc.AddMember("extras", *mAsset.extras, mAl);
849
0
        }
850
0
    }
851
852
    inline void AssetWriter::WriteFile(const char* path)
853
0
    {
854
0
        std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
855
0
856
0
        if (jsonOutFile == nullptr) {
857
0
            throw DeadlyExportError("Could not open output file: " + std::string(path));
858
0
        }
859
0
860
0
        StringBuffer docBuffer;
861
0
862
0
        PrettyWriter<StringBuffer> writer(docBuffer);
863
0
        if (!mDoc.Accept(writer)) {
864
0
            throw DeadlyExportError("Failed to write scene data!");
865
0
        }
866
0
867
0
        if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
868
0
            throw DeadlyExportError("Failed to write scene data!");
869
0
        }
870
0
871
0
        // Write buffer data to separate .bin files
872
0
        for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) {
873
0
            Ref<Buffer> b = mAsset.buffers.Get(i);
874
0
875
0
            std::string binPath = b->GetURI();
876
0
877
0
            std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
878
0
879
0
            if (binOutFile == nullptr) {
880
0
                throw DeadlyExportError("Could not open output file: " + binPath);
881
0
            }
882
0
883
0
            if (b->byteLength > 0) {
884
0
                if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
885
0
                    throw DeadlyExportError("Failed to write binary file: " + binPath);
886
0
                }
887
0
            }
888
0
        }
889
0
    }
890
891
    inline void AssetWriter::WriteGLBFile(const char* path)
892
0
    {
893
0
        std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
894
895
0
        if (outfile == nullptr) {
896
0
            throw DeadlyExportError("Could not open output file: " + std::string(path));
897
0
        }
898
899
0
        Ref<Buffer> bodyBuffer = mAsset.GetBodyBuffer();
900
0
        if (bodyBuffer->byteLength > 0) {
901
0
            rapidjson::Value glbBodyBuffer;
902
0
            glbBodyBuffer.SetObject();
903
0
            glbBodyBuffer.AddMember("byteLength", static_cast<uint64_t>(bodyBuffer->byteLength), mAl);
904
0
            mDoc["buffers"].PushBack(glbBodyBuffer, mAl);
905
0
        }
906
907
        // Padding with spaces as required by the spec
908
0
        uint32_t padding = 0x20202020;
909
910
        //
911
        // JSON chunk
912
        //
913
914
0
        StringBuffer docBuffer;
915
0
        Writer<StringBuffer> writer(docBuffer);
916
0
        if (!mDoc.Accept(writer)) {
917
0
            throw DeadlyExportError("Failed to write scene data!");
918
0
        }
919
920
0
        uint32_t jsonChunkLength = static_cast<uint32_t>((docBuffer.GetSize() + 3) & ~3); // Round up to next multiple of 4
921
0
        auto paddingLength = jsonChunkLength - docBuffer.GetSize();
922
923
0
        GLB_Chunk jsonChunk;
924
0
        jsonChunk.chunkLength = jsonChunkLength;
925
0
        jsonChunk.chunkType = ChunkType_JSON;
926
0
        AI_SWAP4(jsonChunk.chunkLength);
927
928
0
        outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
929
0
        if (outfile->Write(&jsonChunk, 1, sizeof(GLB_Chunk)) != sizeof(GLB_Chunk)) {
930
0
            throw DeadlyExportError("Failed to write scene data header!");
931
0
        }
932
0
        if (outfile->Write(docBuffer.GetString(), 1, docBuffer.GetSize()) != docBuffer.GetSize()) {
933
0
            throw DeadlyExportError("Failed to write scene data!");
934
0
        }
935
0
        if (paddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) {
936
0
            throw DeadlyExportError("Failed to write scene data padding!");
937
0
        }
938
939
        //
940
        // Binary chunk
941
        //
942
943
0
        int GLB_Chunk_count = 1;
944
0
        uint32_t binaryChunkLength = 0;
945
0
        if (bodyBuffer->byteLength > 0) {
946
0
            binaryChunkLength = static_cast<uint32_t>((bodyBuffer->byteLength + 3) & ~3); // Round up to next multiple of 4
947
948
0
            auto curPaddingLength = binaryChunkLength - bodyBuffer->byteLength;
949
0
            ++GLB_Chunk_count;
950
951
0
            GLB_Chunk binaryChunk;
952
0
            binaryChunk.chunkLength = binaryChunkLength;
953
0
            binaryChunk.chunkType = ChunkType_BIN;
954
0
            AI_SWAP4(binaryChunk.chunkLength);
955
956
0
            size_t bodyOffset = sizeof(GLB_Header) + sizeof(GLB_Chunk) + jsonChunk.chunkLength;
957
0
            outfile->Seek(bodyOffset, aiOrigin_SET);
958
0
            if (outfile->Write(&binaryChunk, 1, sizeof(GLB_Chunk)) != sizeof(GLB_Chunk)) {
959
0
                throw DeadlyExportError("Failed to write body data header!");
960
0
            }
961
0
            if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) {
962
0
                throw DeadlyExportError("Failed to write body data!");
963
0
            }
964
0
            if (curPaddingLength && outfile->Write(&padding, 1, curPaddingLength) != curPaddingLength) {
965
0
                throw DeadlyExportError("Failed to write body data padding!");
966
0
            }
967
0
        }
968
969
        //
970
        // Header
971
        //
972
973
0
        GLB_Header header;
974
0
        memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
975
976
0
        header.version = 2;
977
0
        AI_SWAP4(header.version);
978
979
0
        header.length = uint32_t(sizeof(GLB_Header) + GLB_Chunk_count * sizeof(GLB_Chunk) + jsonChunkLength + binaryChunkLength);
980
0
        AI_SWAP4(header.length);
981
982
0
        outfile->Seek(0, aiOrigin_SET);
983
0
        if (outfile->Write(&header, 1, sizeof(GLB_Header)) != sizeof(GLB_Header)) {
984
0
            throw DeadlyExportError("Failed to write the header!");
985
0
        }
986
0
    }
Unexecuted instantiation: glTF2::AssetWriter::WriteGLBFile(char const*)
Unexecuted instantiation: glTF2::AssetWriter::WriteGLBFile(char const*)
987
988
    inline void AssetWriter::WriteMetadata()
989
0
    {
990
0
        Value asset;
991
0
        asset.SetObject();
992
0
        asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
993
0
        asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
994
0
        if (!mAsset.asset.copyright.empty())
995
0
            asset.AddMember("copyright", Value(mAsset.asset.copyright, mAl).Move(), mAl);
996
0
        mDoc.AddMember("asset", asset, mAl);
997
0
    }
998
999
    inline void AssetWriter::WriteExtensionsUsed()
1000
0
    {
1001
0
        Value exts;
1002
0
        exts.SetArray();
1003
0
        {
1004
0
            // This is used to export pbrSpecularGlossiness materials with GLTF 2.
1005
0
            if (this->mAsset.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
1006
0
                exts.PushBack(StringRef("KHR_materials_pbrSpecularGlossiness"), mAl);
1007
0
            }
1008
0
1009
0
            if (this->mAsset.extensionsUsed.KHR_materials_unlit) {
1010
0
              exts.PushBack(StringRef("KHR_materials_unlit"), mAl);
1011
0
            }
1012
0
1013
0
            if (this->mAsset.extensionsUsed.KHR_materials_specular) {
1014
0
                exts.PushBack(StringRef("KHR_materials_specular"), mAl);
1015
0
            }
1016
0
1017
0
            if (this->mAsset.extensionsUsed.KHR_materials_sheen) {
1018
0
                exts.PushBack(StringRef("KHR_materials_sheen"), mAl);
1019
0
            }
1020
0
1021
0
            if (this->mAsset.extensionsUsed.KHR_materials_clearcoat) {
1022
0
                exts.PushBack(StringRef("KHR_materials_clearcoat"), mAl);
1023
0
            }
1024
0
1025
0
            if (this->mAsset.extensionsUsed.KHR_materials_transmission) {
1026
0
                exts.PushBack(StringRef("KHR_materials_transmission"), mAl);
1027
0
            }
1028
0
1029
0
            if (this->mAsset.extensionsUsed.KHR_materials_volume) {
1030
0
                exts.PushBack(StringRef("KHR_materials_volume"), mAl);
1031
0
            }
1032
0
1033
0
            if (this->mAsset.extensionsUsed.KHR_materials_ior) {
1034
0
                exts.PushBack(StringRef("KHR_materials_ior"), mAl);
1035
0
            }
1036
0
1037
0
            if (this->mAsset.extensionsUsed.KHR_materials_emissive_strength) {
1038
0
                exts.PushBack(StringRef("KHR_materials_emissive_strength"), mAl);
1039
0
            }
1040
0
1041
0
            if (this->mAsset.extensionsUsed.KHR_materials_anisotropy) {
1042
0
                exts.PushBack(StringRef("KHR_materials_anisotropy"), mAl);
1043
0
            }
1044
0
1045
0
            if (this->mAsset.extensionsUsed.FB_ngon_encoding) {
1046
0
                exts.PushBack(StringRef("FB_ngon_encoding"), mAl);
1047
0
            }
1048
0
1049
0
            if (this->mAsset.extensionsUsed.KHR_texture_basisu) {
1050
0
                exts.PushBack(StringRef("KHR_texture_basisu"), mAl);
1051
0
            }
1052
0
        }
1053
0
1054
0
        if (!exts.Empty())
1055
0
            mDoc.AddMember("extensionsUsed", exts, mAl);
1056
0
1057
0
        //basisu extensionRequired
1058
0
        Value extsReq;
1059
0
        extsReq.SetArray();
1060
0
        if (this->mAsset.extensionsUsed.KHR_texture_basisu) {
1061
0
            extsReq.PushBack(StringRef("KHR_texture_basisu"), mAl);
1062
0
            mDoc.AddMember("extensionsRequired", extsReq, mAl);
1063
0
        }
1064
0
    }
1065
1066
    template<class T>
1067
    void AssetWriter::WriteObjects(LazyDict<T>& d)
1068
0
    {
1069
0
        if (d.mObjs.empty()) return;
1070
1071
0
        Value* container = &mDoc;
1072
0
        const char* context = "Document";
1073
1074
0
        if (d.mExtId) {
1075
0
            Value* exts = FindObject(mDoc, "extensions");
1076
0
            if (nullptr != exts) {
1077
0
                mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator());
1078
0
                exts = FindObject(mDoc, "extensions");
1079
0
            }
1080
1081
0
            container = FindObjectInContext(*exts, d.mExtId, "extensions");
1082
0
            if (nullptr != container) {
1083
0
                exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
1084
0
                container = FindObjectInContext(*exts, d.mExtId, "extensions");
1085
0
                context = d.mExtId;
1086
0
            }
1087
0
        }
1088
1089
0
        Value *dict = FindArrayInContext(*container, d.mDictId, context);
1090
0
        if (nullptr == dict) {
1091
0
            container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator());
1092
0
            dict = FindArrayInContext(*container, d.mDictId, context);
1093
0
            if (nullptr == dict) {
1094
0
                return;
1095
0
            }
1096
0
        }
1097
1098
0
        for (size_t i = 0; i < d.mObjs.size(); ++i) {
1099
0
            if (d.mObjs[i]->IsSpecial()) {
1100
0
                continue;
1101
0
            }
1102
1103
0
            Value obj;
1104
0
            obj.SetObject();
1105
1106
0
            if (!d.mObjs[i]->name.empty()) {
1107
0
                obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl);
1108
0
            }
1109
1110
0
            Write(obj, *d.mObjs[i], *this);
1111
1112
0
            dict->PushBack(obj, mAl);
1113
0
        }
1114
0
    }
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Accessor>(glTF2::LazyDict<glTF2::Accessor>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Animation>(glTF2::LazyDict<glTF2::Animation>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Buffer>(glTF2::LazyDict<glTF2::Buffer>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::BufferView>(glTF2::LazyDict<glTF2::BufferView>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Camera>(glTF2::LazyDict<glTF2::Camera>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Light>(glTF2::LazyDict<glTF2::Light>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Image>(glTF2::LazyDict<glTF2::Image>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Material>(glTF2::LazyDict<glTF2::Material>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Mesh>(glTF2::LazyDict<glTF2::Mesh>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Node>(glTF2::LazyDict<glTF2::Node>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Sampler>(glTF2::LazyDict<glTF2::Sampler>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Scene>(glTF2::LazyDict<glTF2::Scene>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Skin>(glTF2::LazyDict<glTF2::Skin>&)
Unexecuted instantiation: void glTF2::AssetWriter::WriteObjects<glTF2::Texture>(glTF2::LazyDict<glTF2::Texture>&)
1115
1116
    template<class T>
1117
    void WriteLazyDict(LazyDict<T>& d, AssetWriter& w)
1118
0
    {
1119
0
        w.WriteObjects(d);
1120
0
    }
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Accessor>(glTF2::LazyDict<glTF2::Accessor>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Animation>(glTF2::LazyDict<glTF2::Animation>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Buffer>(glTF2::LazyDict<glTF2::Buffer>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::BufferView>(glTF2::LazyDict<glTF2::BufferView>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Camera>(glTF2::LazyDict<glTF2::Camera>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Light>(glTF2::LazyDict<glTF2::Light>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Image>(glTF2::LazyDict<glTF2::Image>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Material>(glTF2::LazyDict<glTF2::Material>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Mesh>(glTF2::LazyDict<glTF2::Mesh>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Node>(glTF2::LazyDict<glTF2::Node>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Sampler>(glTF2::LazyDict<glTF2::Sampler>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Scene>(glTF2::LazyDict<glTF2::Scene>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Skin>(glTF2::LazyDict<glTF2::Skin>&, glTF2::AssetWriter&)
Unexecuted instantiation: void glTF2::WriteLazyDict<glTF2::Texture>(glTF2::LazyDict<glTF2::Texture>&, glTF2::AssetWriter&)
1121
1122
}