Coverage Report

Created: 2024-08-02 07:04

/src/assimp/code/AssetLib/Assjson/json_exporter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
Assimp2Json
3
Copyright (c) 2011, Alexander C. Gessler
4
5
Licensed under a 3-clause BSD license. See the LICENSE file for more information.
6
7
*/
8
9
#ifndef ASSIMP_BUILD_NO_EXPORT
10
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
11
12
#include <assimp/scene.h>
13
#include <assimp/ai_assert.h>
14
#include <assimp/Exporter.hpp>
15
#include <assimp/IOStream.hpp>
16
#include <assimp/IOSystem.hpp>
17
#include <assimp/Importer.hpp>
18
#include <assimp/Exceptional.h>
19
20
#include <cassert>
21
#include <limits>
22
#include <memory>
23
#include <sstream>
24
25
0
#define CURRENT_FORMAT_VERSION 100
26
27
#include "mesh_splitter.h"
28
29
extern "C" {
30
#   include "cencode.h"
31
}
32
33
namespace Assimp {
34
35
// Forward declarations
36
void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
37
38
// small utility class to simplify serializing the aiScene to Json
39
class JSONWriter {
40
public:
41
    enum {
42
        Flag_DoNotIndent = 0x1,
43
        Flag_WriteSpecialFloats = 0x2,
44
        Flag_SkipWhitespaces = 0x4
45
    };
46
47
    JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
48
0
            out(out), indent (""), newline("\n"), space(" "), buff (), first(false), flags(flags) {
49
        // make sure that all formatting happens using the standard, C locale and not the user's current locale
50
0
        buff.imbue(std::locale("C"));
51
0
        if (flags & Flag_SkipWhitespaces) {
52
0
            newline = "";
53
0
            space = "";
54
0
        }
55
0
    }
56
57
0
    ~JSONWriter() {
58
0
        Flush();
59
0
    }
60
61
0
    void Flush() {
62
0
        const std::string s = buff.str();
63
0
        out.Write(s.c_str(), s.length(), 1);
64
0
        buff.clear();
65
0
    }
66
67
0
    void PushIndent() {
68
0
        indent += '\t';
69
0
    }
70
71
0
    void PopIndent() {
72
0
        indent.erase(indent.end() - 1);
73
0
    }
74
75
0
    void Key(const std::string &name) {
76
0
        AddIndentation();
77
0
        Delimit();
78
0
        buff << '\"' + name + "\":" << space;
79
0
    }
80
81
    template <typename Literal>
82
0
    void Element(const Literal &name) {
83
0
        AddIndentation();
84
0
        Delimit();
85
86
0
        LiteralToString(buff, name) << newline;
87
0
    }
Unexecuted instantiation: void Assimp::JSONWriter::Element<float>(float const&)
Unexecuted instantiation: void Assimp::JSONWriter::Element<unsigned int>(unsigned int const&)
Unexecuted instantiation: void Assimp::JSONWriter::Element<double>(double const&)
Unexecuted instantiation: void Assimp::JSONWriter::Element<int>(int const&)
88
89
    template <typename Literal>
90
0
    void SimpleValue(const Literal &s) {
91
0
        LiteralToString(buff, s) << newline;
92
0
    }
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<char [14]>(char const (&) [14])
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<int>(int const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<aiString>(aiString const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<unsigned int>(unsigned int const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<aiPropertyTypeInfo>(aiPropertyTypeInfo const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<float>(float const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<double>(double const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<aiAnimBehaviour>(aiAnimBehaviour const&)
Unexecuted instantiation: void Assimp::JSONWriter::SimpleValue<aiLightSourceType>(aiLightSourceType const&)
93
94
0
    void SimpleValue(const void *buffer, size_t len) {
95
0
        base64_encodestate s;
96
0
        base64_init_encodestate(&s);
97
98
0
        char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
99
0
        const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
100
0
        cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
101
102
        // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
103
        // (only escaped ones). Remove any newlines in out.
104
0
        for (char *cur = cur_out; *cur; ++cur) {
105
0
            if (*cur == '\n') {
106
0
                *cur = ' ';
107
0
            }
108
0
        }
109
110
0
        buff << '\"' << cur_out << "\"" << newline;
111
0
        delete[] cur_out;
112
0
    }
113
114
0
    void StartObj(bool is_element = false) {
115
        // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
116
0
        if (is_element) {
117
0
            AddIndentation();
118
0
            if (!first) {
119
0
                buff << ',';
120
0
            }
121
0
        }
122
0
        first = true;
123
0
        buff << "{" << newline;
124
0
        PushIndent();
125
0
    }
126
127
0
    void EndObj() {
128
0
        PopIndent();
129
0
        AddIndentation();
130
0
        first = false;
131
0
        buff << "}" << newline;
132
0
    }
133
134
0
    void StartArray(bool is_element = false) {
135
        // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
136
0
        if (is_element) {
137
0
            AddIndentation();
138
0
            if (!first) {
139
0
                buff << ',';
140
0
            }
141
0
        }
142
0
        first = true;
143
0
        buff << "[" << newline;
144
0
        PushIndent();
145
0
    }
146
147
0
    void EndArray() {
148
0
        PopIndent();
149
0
        AddIndentation();
150
0
        buff << "]" << newline;
151
0
        first = false;
152
0
    }
153
154
0
    void AddIndentation() {
155
0
        if (!(flags & Flag_DoNotIndent) && !(flags & Flag_SkipWhitespaces)) {
156
0
            buff << indent;
157
0
        }
158
0
    }
159
160
0
    void Delimit() {
161
0
        if (!first) {
162
0
            buff << ',';
163
0
        } else {
164
0
            buff << space;
165
0
            first = false;
166
0
        }
167
0
    }
168
169
private:
170
    template <typename Literal>
171
0
    std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
172
0
        stream << s;
173
0
        return stream;
174
0
    }
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<char [14]>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, char const (&) [14])
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<int>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, int const&)
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<unsigned int>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, unsigned int const&)
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<aiPropertyTypeInfo>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, aiPropertyTypeInfo const&)
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<double>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, double const&)
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<aiAnimBehaviour>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, aiAnimBehaviour const&)
Unexecuted instantiation: std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& Assimp::JSONWriter::LiteralToString<aiLightSourceType>(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, aiLightSourceType const&)
175
176
0
    std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
177
0
        std::string t;
178
179
        // escape backslashes and single quotes, both would render the JSON invalid if left as is
180
0
        t.reserve(s.length);
181
0
        for (size_t i = 0; i < s.length; ++i) {
182
0
            if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') {
183
0
                t.push_back('\\');
184
0
            }
185
186
0
            t.push_back(s.data[i]);
187
0
        }
188
0
        stream << "\"";
189
0
        stream << t;
190
0
        stream << "\"";
191
0
        return stream;
192
0
    }
193
194
0
    std::stringstream &LiteralToString(std::stringstream &stream, float f) {
195
0
        if (!std::numeric_limits<float>::is_iec559) {
196
            // on a non IEEE-754 platform, we make no assumptions about the representation or existence
197
            // of special floating-point numbers.
198
0
            stream << f;
199
0
            return stream;
200
0
        }
201
202
        // JSON does not support writing Inf/Nan
203
        // [RFC 4672: "Numeric values that cannot be represented as sequences of digits
204
        // (such as Infinity and NaN) are not permitted."]
205
        // Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN
206
0
        if (std::numeric_limits<float>::infinity() == fabs(f)) {
207
0
            if (flags & Flag_WriteSpecialFloats) {
208
0
                stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\"");
209
0
                return stream;
210
0
            }
211
            //  we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
212
            //  std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
213
0
            stream << "0.0";
214
0
            return stream;
215
0
        }
216
        // f!=f is the most reliable test for NaNs that I know of
217
0
        else if (f != f) {
218
0
            if (flags & Flag_WriteSpecialFloats) {
219
0
                stream << "\"NaN\"";
220
0
                return stream;
221
0
            }
222
            //  we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
223
            //  std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
224
0
            stream << "0.0";
225
0
            return stream;
226
0
        }
227
228
0
        stream << f;
229
0
        return stream;
230
0
    }
231
232
private:
233
    Assimp::IOStream &out;
234
    std::string indent;
235
    std::string newline;
236
    std::string space;
237
    std::stringstream buff;
238
    bool first;
239
240
    unsigned int flags;
241
};
242
243
0
static void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
244
0
    out.StartArray(is_elem);
245
0
    out.Element(ai.x);
246
0
    out.Element(ai.y);
247
0
    out.Element(ai.z);
248
0
    out.EndArray();
249
0
}
250
251
0
static void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
252
0
    out.StartArray(is_elem);
253
0
    out.Element(ai.w);
254
0
    out.Element(ai.x);
255
0
    out.Element(ai.y);
256
0
    out.Element(ai.z);
257
0
    out.EndArray();
258
0
}
259
260
0
static void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
261
0
    out.StartArray(is_elem);
262
0
    out.Element(ai.r);
263
0
    out.Element(ai.g);
264
0
    out.Element(ai.b);
265
0
    out.EndArray();
266
0
}
267
268
0
static void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
269
0
    out.StartArray(is_elem);
270
0
    for (unsigned int x = 0; x < 4; ++x) {
271
0
        for (unsigned int y = 0; y < 4; ++y) {
272
0
            out.Element(ai[x][y]);
273
0
        }
274
0
    }
275
0
    out.EndArray();
276
0
}
277
278
0
static void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
279
0
    out.StartObj(is_elem);
280
281
0
    out.Key("name");
282
0
    out.SimpleValue(ai.mName);
283
284
0
    out.Key("offsetmatrix");
285
0
    Write(out, ai.mOffsetMatrix, false);
286
287
0
    out.Key("weights");
288
0
    out.StartArray();
289
0
    for (unsigned int i = 0; i < ai.mNumWeights; ++i) {
290
0
        out.StartArray(true);
291
0
        out.Element(ai.mWeights[i].mVertexId);
292
0
        out.Element(ai.mWeights[i].mWeight);
293
0
        out.EndArray();
294
0
    }
295
0
    out.EndArray();
296
0
    out.EndObj();
297
0
}
298
299
0
static void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
300
0
    out.StartArray(is_elem);
301
0
    for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
302
0
        out.Element(ai.mIndices[i]);
303
0
    }
304
0
    out.EndArray();
305
0
}
306
307
0
static void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
308
0
    out.StartObj(is_elem);
309
310
0
    out.Key("name");
311
0
    out.SimpleValue(ai.mName);
312
313
0
    out.Key("materialindex");
314
0
    out.SimpleValue(ai.mMaterialIndex);
315
316
0
    out.Key("primitivetypes");
317
0
    out.SimpleValue(ai.mPrimitiveTypes);
318
319
0
    out.Key("vertices");
320
0
    out.StartArray();
321
0
    for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
322
0
        out.Element(ai.mVertices[i].x);
323
0
        out.Element(ai.mVertices[i].y);
324
0
        out.Element(ai.mVertices[i].z);
325
0
    }
326
0
    out.EndArray();
327
328
0
    if (ai.HasNormals()) {
329
0
        out.Key("normals");
330
0
        out.StartArray();
331
0
        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
332
0
            out.Element(ai.mNormals[i].x);
333
0
            out.Element(ai.mNormals[i].y);
334
0
            out.Element(ai.mNormals[i].z);
335
0
        }
336
0
        out.EndArray();
337
0
    }
338
339
0
    if (ai.HasTangentsAndBitangents()) {
340
0
        out.Key("tangents");
341
0
        out.StartArray();
342
0
        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
343
0
            out.Element(ai.mTangents[i].x);
344
0
            out.Element(ai.mTangents[i].y);
345
0
            out.Element(ai.mTangents[i].z);
346
0
        }
347
0
        out.EndArray();
348
349
0
        out.Key("bitangents");
350
0
        out.StartArray();
351
0
        for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
352
0
            out.Element(ai.mBitangents[i].x);
353
0
            out.Element(ai.mBitangents[i].y);
354
0
            out.Element(ai.mBitangents[i].z);
355
0
        }
356
0
        out.EndArray();
357
0
    }
358
359
0
    if (ai.GetNumUVChannels()) {
360
0
        out.Key("numuvcomponents");
361
0
        out.StartArray();
362
0
        for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
363
0
            out.Element(ai.mNumUVComponents[n]);
364
0
        }
365
0
        out.EndArray();
366
367
0
        out.Key("texturecoords");
368
0
        out.StartArray();
369
0
        for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
370
0
            const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2;
371
372
0
            out.StartArray(true);
373
0
            for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
374
0
                for (unsigned int c = 0; c < numc; ++c) {
375
0
                    out.Element(ai.mTextureCoords[n][i][c]);
376
0
                }
377
0
            }
378
0
            out.EndArray();
379
0
        }
380
0
        out.EndArray();
381
0
    }
382
383
0
    if (ai.GetNumColorChannels()) {
384
0
        out.Key("colors");
385
0
        out.StartArray();
386
0
        for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) {
387
0
            out.StartArray(true);
388
0
            for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
389
0
                out.Element(ai.mColors[n][i].r);
390
0
                out.Element(ai.mColors[n][i].g);
391
0
                out.Element(ai.mColors[n][i].b);
392
0
                out.Element(ai.mColors[n][i].a);
393
0
            }
394
0
            out.EndArray();
395
0
        }
396
0
        out.EndArray();
397
0
    }
398
399
0
    if (ai.mNumBones) {
400
0
        out.Key("bones");
401
0
        out.StartArray();
402
0
        for (unsigned int n = 0; n < ai.mNumBones; ++n) {
403
0
            Write(out, *ai.mBones[n]);
404
0
        }
405
0
        out.EndArray();
406
0
    }
407
408
0
    out.Key("faces");
409
0
    out.StartArray();
410
0
    for (unsigned int n = 0; n < ai.mNumFaces; ++n) {
411
0
        Write(out, ai.mFaces[n]);
412
0
    }
413
0
    out.EndArray();
414
415
0
    out.EndObj();
416
0
}
417
418
0
static void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
419
0
    out.StartObj(is_elem);
420
421
0
    out.Key("name");
422
0
    out.SimpleValue(ai.mName);
423
424
0
    out.Key("transformation");
425
0
    Write(out, ai.mTransformation, false);
426
427
0
    if (ai.mNumMeshes) {
428
0
        out.Key("meshes");
429
0
        out.StartArray();
430
0
        for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
431
0
            out.Element(ai.mMeshes[n]);
432
0
        }
433
0
        out.EndArray();
434
0
    }
435
436
0
    if (ai.mNumChildren) {
437
0
        out.Key("children");
438
0
        out.StartArray();
439
0
        for (unsigned int n = 0; n < ai.mNumChildren; ++n) {
440
0
            Write(out, *ai.mChildren[n]);
441
0
        }
442
0
        out.EndArray();
443
0
    }
444
445
0
    out.EndObj();
446
0
}
447
448
0
static void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
449
0
    out.StartObj(is_elem);
450
451
0
    out.Key("properties");
452
0
    out.StartArray();
453
0
    for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
454
0
        const aiMaterialProperty *const prop = ai.mProperties[i];
455
0
        out.StartObj(true);
456
0
        out.Key("key");
457
0
        out.SimpleValue(prop->mKey);
458
0
        out.Key("semantic");
459
0
        out.SimpleValue(prop->mSemantic);
460
0
        out.Key("index");
461
0
        out.SimpleValue(prop->mIndex);
462
463
0
        out.Key("type");
464
0
        out.SimpleValue(prop->mType);
465
466
0
        out.Key("value");
467
0
        switch (prop->mType) {
468
0
            case aiPTI_Float:
469
0
                if (prop->mDataLength / sizeof(float) > 1) {
470
0
                    out.StartArray();
471
0
                    for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
472
0
                        out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
473
0
                    }
474
0
                    out.EndArray();
475
0
                } else {
476
0
                    out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
477
0
                }
478
0
                break;
479
0
            case aiPTI_Double:
480
0
                if (prop->mDataLength / sizeof(double) > 1) {
481
0
                    out.StartArray();
482
0
                    for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(double); ++ii) {
483
0
                        out.Element(reinterpret_cast<double*>(prop->mData)[ii]);
484
0
                    }
485
0
                    out.EndArray();
486
0
                } else {
487
0
                    out.SimpleValue(*reinterpret_cast<double*>(prop->mData));
488
0
                }
489
0
                break;
490
0
            case aiPTI_Integer:
491
0
                if (prop->mDataLength / sizeof(int) > 1) {
492
0
                    out.StartArray();
493
0
                    for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
494
0
                        out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
495
0
                    }
496
0
                    out.EndArray();
497
0
                } else {
498
0
                    out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
499
0
                }
500
0
                break;
501
502
0
            case aiPTI_String:
503
0
                {
504
0
                    aiString s;
505
0
                    aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
506
0
                    out.SimpleValue(s);
507
0
                }
508
0
                break;
509
0
            case aiPTI_Buffer:
510
0
                {
511
                    // binary data is written as series of hex-encoded octets
512
0
                    out.SimpleValue(prop->mData, prop->mDataLength);
513
0
                }
514
0
                break;
515
0
            default:
516
0
                ai_assert(false);
517
0
        }
518
519
0
        out.EndObj();
520
0
    }
521
522
0
    out.EndArray();
523
0
    out.EndObj();
524
0
}
525
526
0
static void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
527
0
    out.StartObj(is_elem);
528
529
0
    out.Key("width");
530
0
    out.SimpleValue(ai.mWidth);
531
532
0
    out.Key("height");
533
0
    out.SimpleValue(ai.mHeight);
534
535
0
    out.Key("formathint");
536
0
    out.SimpleValue(aiString(ai.achFormatHint));
537
538
0
    out.Key("data");
539
0
    if (!ai.mHeight) {
540
0
        out.SimpleValue(ai.pcData, ai.mWidth);
541
0
    } else {
542
0
        out.StartArray();
543
0
        for (unsigned int y = 0; y < ai.mHeight; ++y) {
544
0
            out.StartArray(true);
545
0
            for (unsigned int x = 0; x < ai.mWidth; ++x) {
546
0
                const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
547
0
                out.StartArray(true);
548
0
                out.Element(static_cast<unsigned int>(tx.r));
549
0
                out.Element(static_cast<unsigned int>(tx.g));
550
0
                out.Element(static_cast<unsigned int>(tx.b));
551
0
                out.Element(static_cast<unsigned int>(tx.a));
552
0
                out.EndArray();
553
0
            }
554
0
            out.EndArray();
555
0
        }
556
0
        out.EndArray();
557
0
    }
558
559
0
    out.EndObj();
560
0
}
561
562
0
static void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
563
0
    out.StartObj(is_elem);
564
565
0
    out.Key("name");
566
0
    out.SimpleValue(ai.mName);
567
568
0
    out.Key("type");
569
0
    out.SimpleValue(ai.mType);
570
571
0
    if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) {
572
0
        out.Key("angleinnercone");
573
0
        out.SimpleValue(ai.mAngleInnerCone);
574
575
0
        out.Key("angleoutercone");
576
0
        out.SimpleValue(ai.mAngleOuterCone);
577
0
    }
578
579
0
    out.Key("attenuationconstant");
580
0
    out.SimpleValue(ai.mAttenuationConstant);
581
582
0
    out.Key("attenuationlinear");
583
0
    out.SimpleValue(ai.mAttenuationLinear);
584
585
0
    out.Key("attenuationquadratic");
586
0
    out.SimpleValue(ai.mAttenuationQuadratic);
587
588
0
    out.Key("diffusecolor");
589
0
    Write(out, ai.mColorDiffuse, false);
590
591
0
    out.Key("specularcolor");
592
0
    Write(out, ai.mColorSpecular, false);
593
594
0
    out.Key("ambientcolor");
595
0
    Write(out, ai.mColorAmbient, false);
596
597
0
    if (ai.mType != aiLightSource_POINT) {
598
0
        out.Key("direction");
599
0
        Write(out, ai.mDirection, false);
600
0
    }
601
602
0
    if (ai.mType != aiLightSource_DIRECTIONAL) {
603
0
        out.Key("position");
604
0
        Write(out, ai.mPosition, false);
605
0
    }
606
607
0
    out.EndObj();
608
0
}
609
610
0
static void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
611
0
    out.StartObj(is_elem);
612
613
0
    out.Key("name");
614
0
    out.SimpleValue(ai.mNodeName);
615
616
0
    out.Key("prestate");
617
0
    out.SimpleValue(ai.mPreState);
618
619
0
    out.Key("poststate");
620
0
    out.SimpleValue(ai.mPostState);
621
622
0
    if (ai.mNumPositionKeys) {
623
0
        out.Key("positionkeys");
624
0
        out.StartArray();
625
0
        for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
626
0
            const aiVectorKey &pos = ai.mPositionKeys[n];
627
0
            out.StartArray(true);
628
0
            out.Element(pos.mTime);
629
0
            Write(out, pos.mValue);
630
0
            out.EndArray();
631
0
        }
632
0
        out.EndArray();
633
0
    }
634
635
0
    if (ai.mNumRotationKeys) {
636
0
        out.Key("rotationkeys");
637
0
        out.StartArray();
638
0
        for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
639
0
            const aiQuatKey &rot = ai.mRotationKeys[n];
640
0
            out.StartArray(true);
641
0
            out.Element(rot.mTime);
642
0
            Write(out, rot.mValue);
643
0
            out.EndArray();
644
0
        }
645
0
        out.EndArray();
646
0
    }
647
648
0
    if (ai.mNumScalingKeys) {
649
0
        out.Key("scalingkeys");
650
0
        out.StartArray();
651
0
        for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
652
0
            const aiVectorKey &scl = ai.mScalingKeys[n];
653
0
            out.StartArray(true);
654
0
            out.Element(scl.mTime);
655
0
            Write(out, scl.mValue);
656
0
            out.EndArray();
657
0
        }
658
0
        out.EndArray();
659
0
    }
660
0
    out.EndObj();
661
0
}
662
663
0
static void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
664
0
    out.StartObj(is_elem);
665
666
0
    out.Key("name");
667
0
    out.SimpleValue(ai.mName);
668
669
0
    out.Key("tickspersecond");
670
0
    out.SimpleValue(ai.mTicksPerSecond);
671
672
0
    out.Key("duration");
673
0
    out.SimpleValue(ai.mDuration);
674
675
0
    out.Key("channels");
676
0
    out.StartArray();
677
0
    for (unsigned int n = 0; n < ai.mNumChannels; ++n) {
678
0
        Write(out, *ai.mChannels[n]);
679
0
    }
680
0
    out.EndArray();
681
0
    out.EndObj();
682
0
}
683
684
0
static void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
685
0
    out.StartObj(is_elem);
686
687
0
    out.Key("name");
688
0
    out.SimpleValue(ai.mName);
689
690
0
    out.Key("aspect");
691
0
    out.SimpleValue(ai.mAspect);
692
693
0
    out.Key("clipplanefar");
694
0
    out.SimpleValue(ai.mClipPlaneFar);
695
696
0
    out.Key("clipplanenear");
697
0
    out.SimpleValue(ai.mClipPlaneNear);
698
699
0
    out.Key("horizontalfov");
700
0
    out.SimpleValue(ai.mHorizontalFOV);
701
702
0
    out.Key("up");
703
0
    Write(out, ai.mUp, false);
704
705
0
    out.Key("lookat");
706
0
    Write(out, ai.mLookAt, false);
707
708
0
    out.EndObj();
709
0
}
710
711
0
static void WriteFormatInfo(JSONWriter &out) {
712
0
    out.StartObj();
713
0
    out.Key("format");
714
0
    out.SimpleValue("\"assimp2json\"");
715
0
    out.Key("version");
716
0
    out.SimpleValue(CURRENT_FORMAT_VERSION);
717
0
    out.EndObj();
718
0
}
719
720
0
static void Write(JSONWriter &out, const aiScene &ai) {
721
0
    out.StartObj();
722
723
0
    out.Key("__metadata__");
724
0
    WriteFormatInfo(out);
725
726
0
    out.Key("rootnode");
727
0
    Write(out, *ai.mRootNode, false);
728
729
0
    out.Key("flags");
730
0
    out.SimpleValue(ai.mFlags);
731
732
0
    if (ai.HasMeshes()) {
733
0
        out.Key("meshes");
734
0
        out.StartArray();
735
0
        for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
736
0
            Write(out, *ai.mMeshes[n]);
737
0
        }
738
0
        out.EndArray();
739
0
    }
740
741
0
    if (ai.HasMaterials()) {
742
0
        out.Key("materials");
743
0
        out.StartArray();
744
0
        for (unsigned int n = 0; n < ai.mNumMaterials; ++n) {
745
0
            Write(out, *ai.mMaterials[n]);
746
0
        }
747
0
        out.EndArray();
748
0
    }
749
750
0
    if (ai.HasAnimations()) {
751
0
        out.Key("animations");
752
0
        out.StartArray();
753
0
        for (unsigned int n = 0; n < ai.mNumAnimations; ++n) {
754
0
            Write(out, *ai.mAnimations[n]);
755
0
        }
756
0
        out.EndArray();
757
0
    }
758
759
0
    if (ai.HasLights()) {
760
0
        out.Key("lights");
761
0
        out.StartArray();
762
0
        for (unsigned int n = 0; n < ai.mNumLights; ++n) {
763
0
            Write(out, *ai.mLights[n]);
764
0
        }
765
0
        out.EndArray();
766
0
    }
767
768
0
    if (ai.HasCameras()) {
769
0
        out.Key("cameras");
770
0
        out.StartArray();
771
0
        for (unsigned int n = 0; n < ai.mNumCameras; ++n) {
772
0
            Write(out, *ai.mCameras[n]);
773
0
        }
774
0
        out.EndArray();
775
0
    }
776
777
0
    if (ai.HasTextures()) {
778
0
        out.Key("textures");
779
0
        out.StartArray();
780
0
        for (unsigned int n = 0; n < ai.mNumTextures; ++n) {
781
0
            Write(out, *ai.mTextures[n]);
782
0
        }
783
0
        out.EndArray();
784
0
    }
785
0
    out.EndObj();
786
0
}
787
788
0
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *pProperties) {
789
0
    std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
790
0
    if (!str) {
791
0
        throw DeadlyExportError("could not open output file");
792
0
    }
793
794
    // get a copy of the scene so we can modify it
795
0
    aiScene *scenecopy_tmp;
796
0
    aiCopyScene(scene, &scenecopy_tmp);
797
798
0
    try {
799
        // split meshes so they fit into a 16 bit index buffer
800
0
        MeshSplitter splitter;
801
0
        splitter.SetLimit(1 << 16);
802
0
        splitter.Execute(scenecopy_tmp);
803
804
        // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
805
806
0
        unsigned int flags = JSONWriter::Flag_WriteSpecialFloats;
807
0
        if (pProperties->GetPropertyBool("JSON_SKIP_WHITESPACES", false)) {
808
0
            flags |= JSONWriter::Flag_SkipWhitespaces;
809
0
        }
810
0
        JSONWriter s(*str, flags);
811
0
        Write(s, *scenecopy_tmp);
812
813
0
    } catch (...) {
814
0
        aiFreeScene(scenecopy_tmp);
815
0
        throw;
816
0
    }
817
0
    aiFreeScene(scenecopy_tmp);
818
0
}
819
820
} // namespace Assimp
821
822
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
823
#endif // ASSIMP_BUILD_NO_EXPORT