Coverage Report

Created: 2025-06-22 07:30

/src/assimp/code/AssetLib/glTF/glTFAssetWriter.inl
Line
Count
Source (jump to first uncovered line)
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2025, assimp team
6
7
All rights reserved.
8
9
Redistribution and use of this software in source and binary forms,
10
with or without modification, are permitted provided that the
11
following conditions are met:
12
13
* Redistributions of source code must retain the above
14
copyright notice, this list of conditions and the
15
following disclaimer.
16
17
* Redistributions in binary form must reproduce the above
18
copyright notice, this list of conditions and the
19
following disclaimer in the documentation and/or other
20
materials provided with the distribution.
21
22
* Neither the name of the assimp team, nor the names of its
23
contributors may be used to endorse or promote products
24
derived from this software without specific prior
25
written permission of the assimp team.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39
----------------------------------------------------------------------
40
*/
41
42
#include <assimp/Base64.hpp>
43
44
#include <rapidjson/stringbuffer.h>
45
#include <rapidjson/writer.h>
46
#include <rapidjson/prettywriter.h>
47
48
#if _MSC_VER
49
#    pragma warning(push)
50
#    pragma warning( disable : 4706)
51
#endif // _MSC_VER
52
53
namespace glTF {
54
55
    using rapidjson::StringBuffer;
56
    using rapidjson::PrettyWriter;
57
    using rapidjson::Writer;
58
    using rapidjson::StringRef;
59
    using rapidjson::StringRef;
60
61
    namespace {
62
63
        template<typename T, size_t N>
64
        inline
65
0
        Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) {
66
0
            val.SetArray();
67
0
            val.Reserve(N, al);
68
0
            for (decltype(N) i = 0; i < N; ++i) {
69
0
                val.PushBack(r[i], al);
70
0
            }
71
0
            return val;
72
0
        }
Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
73
74
        template<typename T>
75
        inline
76
0
        Value& MakeValue(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
77
0
            val.SetArray();
78
0
            val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
79
0
            for (unsigned int i = 0; i < r.size(); ++i) {
80
0
                val.PushBack(r[i], al);
81
0
            }
82
0
            return val;
83
0
        }
Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(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: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(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>&)
84
85
        template<typename C, typename T>
86
0
        inline Value& MakeValueCast(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
87
0
            val.SetArray();
88
0
            val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
89
0
            for (unsigned int i = 0; i < r.size(); ++i) {
90
0
                val.PushBack(static_cast<C>(r[i]), al);
91
0
            }
92
0
            return val;
93
0
        }
Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(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: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(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>&)
94
95
        template<class T>
96
0
        inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
97
0
            if (v.empty()) return;
98
0
            Value lst;
99
0
            lst.SetArray();
100
0
            lst.Reserve(unsigned(v.size()), al);
101
0
            for (size_t i = 0; i < v.size(); ++i) {
102
0
                lst.PushBack(StringRef(v[i]->id), al);
103
0
            }
104
0
            obj.AddMember(StringRef(fieldId), lst, al);
105
0
        }
Unexecuted instantiation: glTFExporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Node>, std::__1::allocator<glTFCommon::Ref<glTF::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFExporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Mesh>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Mesh>, std::__1::allocator<glTFCommon::Ref<glTF::Mesh> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Node>, std::__1::allocator<glTFCommon::Ref<glTF::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Mesh>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Mesh>, std::__1::allocator<glTFCommon::Ref<glTF::Mesh> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
106
107
108
    }
109
110
    inline void Write(Value& obj, Accessor& a, AssetWriter& w)
111
0
    {
112
0
        obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl);
113
0
        obj.AddMember("byteOffset", a.byteOffset, w.mAl);
114
0
        obj.AddMember("byteStride", a.byteStride, w.mAl);
115
0
        obj.AddMember("componentType", int(a.componentType), w.mAl);
116
0
        obj.AddMember("count", a.count, w.mAl);
117
0
        obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
118
119
0
        Value vTmpMax, vTmpMin;
120
0
    if (a.componentType == ComponentType_FLOAT) {
121
0
      obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
122
0
      obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
123
0
    } else {
124
0
      obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
125
0
      obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
126
0
    }
127
0
    }
128
129
    inline void Write(Value& obj, Animation& a, AssetWriter& w)
130
0
    {
131
        /****************** Channels *******************/
132
0
        Value channels;
133
0
        channels.SetArray();
134
0
        channels.Reserve(unsigned(a.Channels.size()), w.mAl);
135
136
0
        for (size_t i = 0; i < unsigned(a.Channels.size()); ++i) {
137
0
            Animation::AnimChannel& c = a.Channels[i];
138
0
            Value valChannel;
139
0
            valChannel.SetObject();
140
0
            {
141
0
                valChannel.AddMember("sampler", c.sampler, w.mAl);
142
143
0
                Value valTarget;
144
0
                valTarget.SetObject();
145
0
                {
146
0
                    valTarget.AddMember("id", StringRef(c.target.id->id), w.mAl);
147
0
                    valTarget.AddMember("path", c.target.path, w.mAl);
148
0
                }
149
0
                valChannel.AddMember("target", valTarget, w.mAl);
150
0
            }
151
0
            channels.PushBack(valChannel, w.mAl);
152
0
        }
153
0
        obj.AddMember("channels", channels, w.mAl);
154
155
        /****************** Parameters *******************/
156
0
        Value valParameters;
157
0
        valParameters.SetObject();
158
0
        {
159
0
            if (a.Parameters.TIME) {
160
0
                valParameters.AddMember("TIME", StringRef(a.Parameters.TIME->id), w.mAl);
161
0
            }
162
0
            if (a.Parameters.rotation) {
163
0
                valParameters.AddMember("rotation", StringRef(a.Parameters.rotation->id), w.mAl);
164
0
            }
165
0
            if (a.Parameters.scale) {
166
0
                valParameters.AddMember("scale", StringRef(a.Parameters.scale->id), w.mAl);
167
0
            }
168
0
            if (a.Parameters.translation) {
169
0
                valParameters.AddMember("translation", StringRef(a.Parameters.translation->id), w.mAl);
170
0
            }
171
0
        }
172
0
        obj.AddMember("parameters", valParameters, w.mAl);
173
174
        /****************** Samplers *******************/
175
0
        Value valSamplers;
176
0
        valSamplers.SetObject();
177
178
0
        for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) {
179
0
            Animation::AnimSampler& s = a.Samplers[i];
180
0
            Value valSampler;
181
0
            valSampler.SetObject();
182
0
            {
183
0
                valSampler.AddMember("input", s.input, w.mAl);
184
0
                valSampler.AddMember("interpolation", s.interpolation, w.mAl);
185
0
                valSampler.AddMember("output", s.output, w.mAl);
186
0
            }
187
0
            valSamplers.AddMember(StringRef(s.id), valSampler, w.mAl);
188
0
        }
189
0
        obj.AddMember("samplers", valSamplers, w.mAl);
190
0
    }
191
192
    inline void Write(Value& obj, Buffer& b, AssetWriter& w)
193
0
    {
194
0
        const char* type;
195
0
        switch (b.type) {
196
0
            case Buffer::Type_text:
197
0
                type = "text"; break;
198
0
            default:
199
0
                type = "arraybuffer";
200
0
        }
201
202
0
        obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
203
0
        obj.AddMember("type", StringRef(type), w.mAl);
204
0
        obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
205
0
    }
206
207
    inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
208
0
    {
209
0
        obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
210
0
        obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
211
0
        obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
212
0
        if (bv.target != BufferViewTarget_NONE) {
213
0
            obj.AddMember("target", int(bv.target), w.mAl);
214
0
        }
215
0
    }
216
217
    inline void Write(Value& /*obj*/, Camera& /*c*/, AssetWriter& /*w*/)
218
0
    {
219
220
0
    }
221
222
    inline void Write(Value& obj, Image& img, AssetWriter& w)
223
0
    {
224
0
        std::string uri;
225
0
        if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) {
226
0
            Value exts, ext;
227
0
            exts.SetObject();
228
0
            ext.SetObject();
229
230
0
            ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl);
231
232
0
            if (!img.mimeType.empty())
233
0
                ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
234
235
0
            exts.AddMember("KHR_binary_glTF", ext, w.mAl);
236
0
            obj.AddMember("extensions", exts, w.mAl);
237
0
            return;
238
0
        }
239
0
        else if (img.HasData()) {
240
0
            uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
241
0
            uri += ";base64,";
242
0
            Base64::Encode(img.GetData(), img.GetDataLength(), uri);
243
0
        }
244
0
        else {
245
0
            uri = img.uri;
246
0
        }
247
248
0
        obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl);
249
0
    }
250
251
    namespace {
252
        inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
253
0
        {
254
0
            if (prop.texture)
255
0
                obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al);
256
0
            else {
257
0
                Value col;
258
0
                obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
259
0
            }
260
0
        }
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::WriteColorOrTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF::TexProperty&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::WriteColorOrTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF::TexProperty&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&)
261
    }
262
263
    inline void Write(Value& obj, Material& m, AssetWriter& w)
264
0
    {
265
0
        Value v;
266
0
        v.SetObject();
267
0
        {
268
0
            WriteColorOrTex(v, m.ambient, "ambient", w.mAl);
269
0
            WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl);
270
0
            WriteColorOrTex(v, m.specular, "specular", w.mAl);
271
0
            WriteColorOrTex(v, m.emission, "emission", w.mAl);
272
273
0
            if (m.transparent)
274
0
                v.AddMember("transparency", m.transparency, w.mAl);
275
276
0
            v.AddMember("shininess", m.shininess, w.mAl);
277
0
        }
278
0
        obj.AddMember("values", v, w.mAl);
279
0
    }
280
281
    namespace {
282
        inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst,
283
            const char* semantic, bool forceNumber = false)
284
0
        {
285
0
            if (lst.empty()) return;
286
0
            if (lst.size() == 1 && !forceNumber) {
287
0
                attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl);
288
0
            }
289
0
            else {
290
0
                for (size_t i = 0; i < lst.size(); ++i) {
291
0
                    char buffer[32];
292
0
                    ai_snprintf(buffer, 32, "%s_%d", semantic, int(i));
293
0
                    attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl);
294
0
                }
295
0
            }
296
0
        }
Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::WriteAttrs(glTF::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >&, char const*, bool)
Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::WriteAttrs(glTF::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >&, char const*, bool)
297
    }
298
299
    inline void Write(Value& obj, Mesh& m, AssetWriter& w)
300
0
    {
301
    /********************* Name **********************/
302
0
    obj.AddMember("name", m.name, w.mAl);
303
304
    /**************** Mesh extensions ****************/
305
0
    if(m.Extension.size() > 0)
306
0
    {
307
0
      Value json_extensions;
308
309
0
      json_extensions.SetObject();
310
0
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
311
0
      for(Mesh::SExtension* ptr_ext : m.Extension)
312
0
      {
313
0
        switch(ptr_ext->Type)
314
0
        {
315
0
          case Mesh::SExtension::EType::Compression_Open3DGC:
316
0
            {
317
0
              Value json_comp_data;
318
0
              Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
319
320
              // filling object "compressedData"
321
0
              json_comp_data.SetObject();
322
0
              json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
323
0
              json_comp_data.AddMember("byteOffset", static_cast<uint64_t>(ptr_ext_comp->Offset), w.mAl);
324
0
              json_comp_data.AddMember("componentType", 5121, w.mAl);
325
0
              json_comp_data.AddMember("type", "SCALAR", w.mAl);
326
0
              json_comp_data.AddMember("count", static_cast<uint64_t>(ptr_ext_comp->Count), w.mAl);
327
0
              if(ptr_ext_comp->Binary)
328
0
                json_comp_data.AddMember("mode", "binary", w.mAl);
329
0
              else
330
0
                json_comp_data.AddMember("mode", "ascii", w.mAl);
331
332
0
              json_comp_data.AddMember("indicesCount", static_cast<uint64_t>(ptr_ext_comp->IndicesCount), w.mAl);
333
0
              json_comp_data.AddMember("verticesCount", static_cast<uint64_t>(ptr_ext_comp->VerticesCount), w.mAl);
334
              // filling object "Open3DGC-compression"
335
0
              Value json_o3dgc;
336
337
0
              json_o3dgc.SetObject();
338
0
              json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
339
              // add member to object "extensions"
340
0
              json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
341
0
            }
342
343
0
            break;
344
0
          default:
345
0
            throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
346
0
        }// switch(ptr_ext->Type)
347
0
      }// for(Mesh::SExtension* ptr_ext : m.Extension)
348
0
#endif
349
350
      // Add extensions to mesh
351
0
      obj.AddMember("extensions", json_extensions, w.mAl);
352
0
    }// if(m.Extension.size() > 0)
353
354
    /****************** Primitives *******************/
355
0
        Value primitives;
356
0
        primitives.SetArray();
357
0
        primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
358
359
0
        for (size_t i = 0; i < m.primitives.size(); ++i) {
360
0
            Mesh::Primitive& p = m.primitives[i];
361
0
            Value prim;
362
0
            prim.SetObject();
363
0
            {
364
0
                prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
365
366
0
                if (p.material)
367
0
                    prim.AddMember("material", p.material->id, w.mAl);
368
369
0
                if (p.indices)
370
0
                    prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl);
371
372
0
                Value attrs;
373
0
                attrs.SetObject();
374
0
                {
375
0
                    WriteAttrs(w, attrs, p.attributes.position, "POSITION");
376
0
                    WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
377
0
                    WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
378
0
                    WriteAttrs(w, attrs, p.attributes.color, "COLOR");
379
0
                    WriteAttrs(w, attrs, p.attributes.joint, "JOINT");
380
0
                    WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX");
381
0
                    WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT");
382
0
                }
383
0
                prim.AddMember("attributes", attrs, w.mAl);
384
0
            }
385
0
            primitives.PushBack(prim, w.mAl);
386
0
        }
387
388
0
        obj.AddMember("primitives", primitives, w.mAl);
389
0
    }
390
391
    inline void Write(Value& obj, Node& n, AssetWriter& w)
392
0
    {
393
394
0
        if (n.matrix.isPresent) {
395
0
            Value val;
396
0
            obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
397
0
        }
398
399
0
        if (n.translation.isPresent) {
400
0
            Value val;
401
0
            obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl);
402
0
        }
403
404
0
        if (n.scale.isPresent) {
405
0
            Value val;
406
0
            obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl);
407
0
        }
408
0
        if (n.rotation.isPresent) {
409
0
            Value val;
410
0
            obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl);
411
0
        }
412
413
0
        AddRefsVector(obj, "children", n.children, w.mAl);
414
415
0
        AddRefsVector(obj, "meshes", n.meshes, w.mAl);
416
417
0
        AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
418
419
0
        if (n.skin) {
420
0
            obj.AddMember("skin", Value(n.skin->id, w.mAl).Move(), w.mAl);
421
0
        }
422
423
0
        if (!n.jointName.empty()) {
424
0
          obj.AddMember("jointName", n.jointName, w.mAl);
425
0
        }
426
0
    }
427
428
    inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
429
0
    {
430
0
431
0
    }
432
433
    inline void Write(Value& obj, Sampler& b, AssetWriter& w)
434
0
    {
435
0
        if (b.wrapS) {
436
0
            obj.AddMember("wrapS", b.wrapS, w.mAl);
437
0
        }
438
0
        if (b.wrapT) {
439
0
            obj.AddMember("wrapT", b.wrapT, w.mAl);
440
0
        }
441
0
        if (b.magFilter) {
442
0
            obj.AddMember("magFilter", b.magFilter, w.mAl);
443
0
        }
444
0
        if (b.minFilter) {
445
0
            obj.AddMember("minFilter", b.minFilter, w.mAl);
446
0
        }
447
0
    }
448
449
    inline void Write(Value& scene, Scene& s, AssetWriter& w)
450
0
    {
451
0
        AddRefsVector(scene, "nodes", s.nodes, w.mAl);
452
0
    }
453
454
    inline void Write(Value& /*obj*/, Shader& /*b*/, AssetWriter& /*w*/)
455
0
    {
456
0
457
0
    }
458
459
    inline void Write(Value& obj, Skin& b, AssetWriter& w)
460
0
    {
461
        /****************** jointNames *******************/
462
0
        Value vJointNames;
463
0
        vJointNames.SetArray();
464
0
        vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
465
466
0
        for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
467
0
            vJointNames.PushBack(StringRef(b.jointNames[i]->jointName), w.mAl);
468
0
        }
469
0
        obj.AddMember("jointNames", vJointNames, w.mAl);
470
471
0
        if (b.bindShapeMatrix.isPresent) {
472
0
            Value val;
473
0
            obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl);
474
0
        }
475
476
0
        if (b.inverseBindMatrices) {
477
0
            obj.AddMember("inverseBindMatrices", Value(b.inverseBindMatrices->id, w.mAl).Move(), w.mAl);
478
0
        }
479
480
0
    }
481
482
    inline void Write(Value& /*obj*/, Technique& /*b*/, AssetWriter& /*w*/)
483
0
    {
484
0
485
0
    }
486
487
    inline void Write(Value& obj, Texture& tex, AssetWriter& w)
488
0
    {
489
0
        if (tex.source) {
490
0
            obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl);
491
0
        }
492
0
        if (tex.sampler) {
493
0
            obj.AddMember("sampler", Value(tex.sampler->id, w.mAl).Move(), w.mAl);
494
0
        }
495
0
    }
496
497
    inline void Write(Value& /*obj*/, Light& /*b*/, AssetWriter& /*w*/)
498
0
    {
499
500
0
    }
501
502
503
    inline AssetWriter::AssetWriter(Asset& a)
504
0
        : mDoc()
505
0
        , mAsset(a)
506
0
        , mAl(mDoc.GetAllocator())
507
0
    {
508
0
        mDoc.SetObject();
509
510
0
        WriteMetadata();
511
0
        WriteExtensionsUsed();
512
513
        // Dump the contents of the dictionaries
514
0
        for (size_t i = 0; i < a.mDicts.size(); ++i) {
515
0
            a.mDicts[i]->WriteObjects(*this);
516
0
        }
517
518
        // Add the target scene field
519
0
        if (mAsset.scene) {
520
0
            mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl);
521
0
        }
522
0
    }
523
524
    inline void AssetWriter::WriteFile(const char* path)
525
0
    {
526
0
        std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
527
528
0
        if (jsonOutFile == nullptr) {
529
0
            throw DeadlyExportError("Could not open output file: " + std::string(path));
530
0
        }
531
532
0
        StringBuffer docBuffer;
533
534
0
        PrettyWriter<StringBuffer> writer(docBuffer);
535
0
        if (!mDoc.Accept(writer)) {
536
0
            throw DeadlyExportError("Failed to write scene data!");
537
0
        }
538
539
0
        if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
540
0
            throw DeadlyExportError("Failed to write scene data!");
541
0
        }
542
543
        // Write buffer data to separate .bin files
544
0
        for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) {
545
0
            Ref<Buffer> b = mAsset.buffers.Get(i);
546
547
0
            std::string binPath = b->GetURI();
548
549
0
            std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
550
551
0
            if (binOutFile == nullptr) {
552
0
                throw DeadlyExportError("Could not open output file: " + binPath);
553
0
            }
554
555
0
            if (b->byteLength > 0) {
556
0
                if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
557
0
                    throw DeadlyExportError("Failed to write binary file: " + binPath);
558
0
                }
559
0
            }
560
0
        }
561
0
    }
562
563
    inline void AssetWriter::WriteGLBFile(const char* path)
564
0
    {
565
0
        std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
566
567
0
        if (outfile == nullptr) {
568
0
            throw DeadlyExportError("Could not open output file: " + std::string(path));
569
0
        }
570
571
        // we will write the header later, skip its size
572
0
        outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
573
574
0
        StringBuffer docBuffer;
575
0
        Writer<StringBuffer> writer(docBuffer);
576
0
        if (!mDoc.Accept(writer)) {
577
0
            throw DeadlyExportError("Failed to write scene data!");
578
0
        }
579
580
0
        if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
581
0
            throw DeadlyExportError("Failed to write scene data!");
582
0
        }
583
584
0
        WriteBinaryData(outfile.get(), docBuffer.GetSize());
585
0
    }
586
587
    inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
588
0
    {
589
        //
590
        // write the body data
591
        //
592
593
0
        size_t bodyLength = 0;
594
0
        if (Ref<Buffer> b = mAsset.GetBodyBuffer()) {
595
0
            bodyLength = b->byteLength;
596
597
0
            if (bodyLength > 0) {
598
0
                size_t bodyOffset = sizeof(GLB_Header) + sceneLength;
599
0
                bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4
600
601
0
                outfile->Seek(bodyOffset, aiOrigin_SET);
602
603
0
                if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
604
0
                    throw DeadlyExportError("Failed to write body data!");
605
0
                }
606
0
            }
607
0
        }
608
609
        //
610
        // write the header
611
        //
612
613
0
        GLB_Header header;
614
0
        memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
615
616
0
        header.version = 1;
617
0
        AI_SWAP4(header.version);
618
619
0
        header.length = uint32_t(sizeof(header) + sceneLength + bodyLength);
620
0
        AI_SWAP4(header.length);
621
622
0
        header.sceneLength = uint32_t(sceneLength);
623
0
        AI_SWAP4(header.sceneLength);
624
625
0
        header.sceneFormat = SceneFormat_JSON;
626
0
        AI_SWAP4(header.sceneFormat);
627
628
0
        outfile->Seek(0, aiOrigin_SET);
629
630
0
        if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) {
631
0
            throw DeadlyExportError("Failed to write the header!");
632
0
        }
633
0
    }
634
635
636
    inline void AssetWriter::WriteMetadata()
637
0
    {
638
0
        Value asset;
639
0
        asset.SetObject();
640
0
        asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
641
0
        asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
642
0
        if (!mAsset.asset.copyright.empty())
643
0
            asset.AddMember("copyright", Value(mAsset.asset.copyright, mAl).Move(), mAl);
644
645
0
        mDoc.AddMember("asset", asset, mAl);
646
0
    }
647
648
    inline void AssetWriter::WriteExtensionsUsed()
649
0
    {
650
0
        Value exts;
651
0
        exts.SetArray();
652
0
        {
653
0
            if (false)
654
0
                exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
655
656
0
            if (false)
657
0
                exts.PushBack(StringRef("KHR_materials_common"), mAl);
658
0
        }
659
660
0
        if (!exts.Empty())
661
0
            mDoc.AddMember("extensionsUsed", exts, mAl);
662
0
    }
663
664
    template<class T>
665
    void AssetWriter::WriteObjects(LazyDict<T>& d)
666
0
    {
667
0
        if (d.mObjs.empty()) return;
668
669
0
        Value* container = &mDoc;
670
671
0
        if (d.mExtId) {
672
0
            Value* exts = FindObject(mDoc, "extensions");
673
0
            if (!exts) {
674
0
                mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator());
675
0
                exts = FindObject(mDoc, "extensions");
676
0
            }
677
678
0
            if (!(container = FindObject(*exts, d.mExtId))) {
679
0
                exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
680
0
                container = FindObject(*exts, d.mExtId);
681
0
            }
682
0
        }
683
684
0
        Value* dict;
685
0
        if (!(dict = FindObject(*container, d.mDictId))) {
686
0
            container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator());
687
0
            dict = FindObject(*container, d.mDictId);
688
0
        }
689
690
0
        for (size_t i = 0; i < d.mObjs.size(); ++i) {
691
0
            if (d.mObjs[i]->IsSpecial()) continue;
692
693
0
            Value obj;
694
0
            obj.SetObject();
695
696
0
            if (!d.mObjs[i]->name.empty()) {
697
0
                obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl);
698
0
            }
699
700
0
            Write(obj, *d.mObjs[i], *this);
701
702
0
            dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl);
703
0
        }
704
0
    }
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Accessor>(glTF::LazyDict<glTF::Accessor>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Animation>(glTF::LazyDict<glTF::Animation>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Buffer>(glTF::LazyDict<glTF::Buffer>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::BufferView>(glTF::LazyDict<glTF::BufferView>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Camera>(glTF::LazyDict<glTF::Camera>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Image>(glTF::LazyDict<glTF::Image>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Material>(glTF::LazyDict<glTF::Material>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Mesh>(glTF::LazyDict<glTF::Mesh>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Node>(glTF::LazyDict<glTF::Node>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Sampler>(glTF::LazyDict<glTF::Sampler>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Scene>(glTF::LazyDict<glTF::Scene>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Skin>(glTF::LazyDict<glTF::Skin>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Texture>(glTF::LazyDict<glTF::Texture>&)
Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Light>(glTF::LazyDict<glTF::Light>&)
705
706
    template<class T>
707
    void WriteLazyDict(LazyDict<T>& d, AssetWriter& w)
708
0
    {
709
0
        w.WriteObjects(d);
710
0
    }
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Accessor>(glTF::LazyDict<glTF::Accessor>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Animation>(glTF::LazyDict<glTF::Animation>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Buffer>(glTF::LazyDict<glTF::Buffer>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::BufferView>(glTF::LazyDict<glTF::BufferView>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Camera>(glTF::LazyDict<glTF::Camera>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Image>(glTF::LazyDict<glTF::Image>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Material>(glTF::LazyDict<glTF::Material>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Mesh>(glTF::LazyDict<glTF::Mesh>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Node>(glTF::LazyDict<glTF::Node>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Sampler>(glTF::LazyDict<glTF::Sampler>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Scene>(glTF::LazyDict<glTF::Scene>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Skin>(glTF::LazyDict<glTF::Skin>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Texture>(glTF::LazyDict<glTF::Texture>&, glTF::AssetWriter&)
Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Light>(glTF::LazyDict<glTF::Light>&, glTF::AssetWriter&)
711
712
#if _MSC_VER
713
#    pragma warning(pop)
714
#endif // _WIN32
715
716
}