Coverage Report

Created: 2026-03-12 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/Assxml/AssxmlFileWriter.cpp
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
/** @file AssxmlFileWriter.cpp
42
 *  @brief Implementation of Assxml file writer.
43
 */
44
45
#include "AssxmlFileWriter.h"
46
47
#include "PostProcessing/ProcessHelper.h"
48
49
#include <assimp/version.h>
50
#include <assimp/Exporter.hpp>
51
#include <assimp/IOStream.hpp>
52
#include <assimp/IOSystem.hpp>
53
54
#include <stdarg.h>
55
56
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
57
#include <zlib.h>
58
#else
59
#include <contrib/zlib/zlib.h>
60
#endif
61
62
#include <stdio.h>
63
#include <time.h>
64
#include <memory>
65
66
using namespace Assimp;
67
68
namespace Assimp {
69
70
namespace AssxmlFileWriter {
71
72
// -----------------------------------------------------------------------------------
73
0
static int ioprintf(IOStream *io, const char *format, ...) {
74
0
    using namespace std;
75
0
    if (nullptr == io) {
76
0
        return -1;
77
0
    }
78
79
0
    static const int Size = 4096;
80
0
    char sz[Size] = {};
81
0
    va_list va;
82
0
    va_start(va, format);
83
0
    const unsigned int nSize = vsnprintf(sz, Size - 1, format, va);
84
0
    ai_assert(nSize < Size);
85
0
    va_end(va);
86
87
0
    io->Write(sz, sizeof(char), nSize);
88
89
0
    return nSize;
90
0
}
91
92
// -----------------------------------------------------------------------------------
93
// Convert a name to standard XML format
94
0
static void ConvertName(aiString &out, const aiString &in) {
95
0
    out.length = 0;
96
0
    for (unsigned int i = 0; i < in.length; ++i) {
97
0
        switch (in.data[i]) {
98
0
        case '<':
99
0
            out.Append("&lt;");
100
0
            break;
101
0
        case '>':
102
0
            out.Append("&gt;");
103
0
            break;
104
0
        case '&':
105
0
            out.Append("&amp;");
106
0
            break;
107
0
        case '\"':
108
0
            out.Append("&quot;");
109
0
            break;
110
0
        case '\'':
111
0
            out.Append("&apos;");
112
0
            break;
113
0
        default:
114
0
            out.data[out.length++] = in.data[i];
115
0
        }
116
0
    }
117
0
    out.data[out.length] = 0;
118
0
}
119
120
// -----------------------------------------------------------------------------------
121
// Write a single node as text dump
122
0
static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
123
0
    char prefix[512];
124
0
    for (unsigned int i = 0; i < depth; ++i)
125
0
        prefix[i] = '\t';
126
0
    prefix[depth] = '\0';
127
128
0
    const aiMatrix4x4 &m = node->mTransformation;
129
130
0
    aiString name;
131
0
    ConvertName(name, node->mName);
132
0
    ioprintf(io, "%s<Node name=\"%s\"> \n"
133
0
                 "%s\t<Matrix4> \n"
134
0
                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
135
0
                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
136
0
                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
137
0
                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
138
0
                 "%s\t</Matrix4> \n",
139
0
            prefix, name.data, prefix,
140
0
            prefix, m.a1, m.a2, m.a3, m.a4,
141
0
            prefix, m.b1, m.b2, m.b3, m.b4,
142
0
            prefix, m.c1, m.c2, m.c3, m.c4,
143
0
            prefix, m.d1, m.d2, m.d3, m.d4, prefix);
144
145
0
    if (node->mNumMeshes) {
146
0
        ioprintf(io, "%s\t<MeshRefs num=\"%u\">\n%s\t",
147
0
                prefix, node->mNumMeshes, prefix);
148
149
0
        for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
150
0
            ioprintf(io, "%u ", node->mMeshes[i]);
151
0
        }
152
0
        ioprintf(io, "\n%s\t</MeshRefs>\n", prefix);
153
0
    }
154
155
0
    if (node->mNumChildren) {
156
0
        ioprintf(io, "%s\t<NodeList num=\"%u\">\n",
157
0
                prefix, node->mNumChildren);
158
159
0
        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
160
0
            WriteNode(node->mChildren[i], io, depth + 2);
161
0
        }
162
0
        ioprintf(io, "%s\t</NodeList>\n", prefix);
163
0
    }
164
0
    ioprintf(io, "%s</Node>\n", prefix);
165
0
}
166
167
// -----------------------------------------------------------------------------------
168
// Some chunks of text will need to be encoded for XML
169
// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
170
0
static std::string encodeXML(const std::string &data) {
171
0
    std::string buffer;
172
0
    buffer.reserve(data.size());
173
0
    for (size_t pos = 0; pos != data.size(); ++pos) {
174
0
        switch (data[pos]) {
175
0
        case '&': buffer.append("&amp;"); break;
176
0
        case '\"': buffer.append("&quot;"); break;
177
0
        case '\'': buffer.append("&apos;"); break;
178
0
        case '<': buffer.append("&lt;"); break;
179
0
        case '>': buffer.append("&gt;"); break;
180
0
        default: buffer.append(&data[pos], 1); break;
181
0
        }
182
0
    }
183
0
    return buffer;
184
0
}
185
186
// -----------------------------------------------------------------------------------
187
// Write a text model dump
188
0
static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) {
189
0
    time_t tt = ::time(nullptr);
190
#if _WIN32
191
    tm *p = gmtime(&tt);
192
#else
193
0
    struct tm now;
194
0
    tm *p = gmtime_r(&tt, &now);
195
0
#endif
196
0
    ai_assert(nullptr != p);
197
198
0
    std::string c = cmd;
199
0
    std::string::size_type s;
200
201
    // https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632
202
    // -- not allowed in XML comments
203
0
    while ((s = c.find("--")) != std::string::npos) {
204
0
        c[s] = '?';
205
0
    }
206
207
    // write header
208
0
    std::string header(
209
0
            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
210
0
            "<ASSIMP format_id=\"1\">\n\n"
211
0
            "<!-- XML Model dump produced by assimp dump\n"
212
0
            "  Library version: %u.%u.%u\n"
213
0
            "  Source: %s\n"
214
0
            "  Command line: %s\n"
215
0
            "  %s\n"
216
0
            "-->"
217
0
            " \n\n"
218
0
            "<Scene flags=\"%u\" postprocessing=\"%u\">\n");
219
220
0
    const unsigned int majorVersion(aiGetVersionMajor());
221
0
    const unsigned int minorVersion(aiGetVersionMinor());
222
0
    const unsigned int rev(aiGetVersionRevision());
223
0
    const char *curtime = asctime(p);
224
0
    ioprintf(io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u);
225
226
    // write the node graph
227
0
    WriteNode(scene->mRootNode, io, 0);
228
229
#if 0
230
    // write cameras
231
    for (unsigned int i = 0; i < scene->mNumCameras;++i) {
232
        aiCamera* cam  = scene->mCameras[i];
233
        ConvertName(name,cam->mName);
234
235
        // camera header
236
        ioprintf(io,"\t<Camera parent=\"%s\">\n"
237
            "\t\t<Vector3 name=\"up\"        > %0 8f %0 8f %0 8f </Vector3>\n"
238
            "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n"
239
            "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
240
            "\t\t<Float   name=\"fov\"       > %f </Float>\n"
241
            "\t\t<Float   name=\"aspect\"    > %f </Float>\n"
242
            "\t\t<Float   name=\"near_clip\" > %f </Float>\n"
243
            "\t\t<Float   name=\"far_clip\"  > %f </Float>\n"
244
            "\t</Camera>\n",
245
            name.data,
246
            cam->mUp.x,cam->mUp.y,cam->mUp.z,
247
            cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
248
            cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
249
            cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
250
    }
251
252
    // write lights
253
    for (unsigned int i = 0; i < scene->mNumLights;++i) {
254
        aiLight* l  = scene->mLights[i];
255
        ConvertName(name,l->mName);
256
257
        // light header
258
        ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
259
            "\t\t<Vector3 name=\"diffuse\"   > %0 8f %0 8f %0 8f </Vector3>\n"
260
            "\t\t<Vector3 name=\"specular\"  > %0 8f %0 8f %0 8f </Vector3>\n"
261
            "\t\t<Vector3 name=\"ambient\"   > %0 8f %0 8f %0 8f </Vector3>\n",
262
            name.data,
263
            (l->mType == aiLightSource_DIRECTIONAL ? "directional" :
264
            (l->mType == aiLightSource_POINT ? "point" : "spot" )),
265
            l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
266
            l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
267
            l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
268
269
        if (l->mType != aiLightSource_DIRECTIONAL) {
270
            ioprintf(io,
271
                "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
272
                "\t\t<Float   name=\"atten_cst\" > %f </Float>\n"
273
                "\t\t<Float   name=\"atten_lin\" > %f </Float>\n"
274
                "\t\t<Float   name=\"atten_sqr\" > %f </Float>\n",
275
                l->mPosition.x,l->mPosition.y,l->mPosition.z,
276
                l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
277
        }
278
279
        if (l->mType != aiLightSource_POINT) {
280
            ioprintf(io,
281
                "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n",
282
                l->mDirection.x,l->mDirection.y,l->mDirection.z);
283
        }
284
285
        if (l->mType == aiLightSource_SPOT) {
286
            ioprintf(io,
287
                "\t\t<Float   name=\"cone_out\" > %f </Float>\n"
288
                "\t\t<Float   name=\"cone_inn\" > %f </Float>\n",
289
                l->mAngleOuterCone,l->mAngleInnerCone);
290
        }
291
        ioprintf(io,"\t</Light>\n");
292
    }
293
#endif
294
0
    aiString name;
295
296
    // write textures
297
0
    if (scene->mNumTextures) {
298
0
        ioprintf(io, "<TextureList num=\"%u\">\n", scene->mNumTextures);
299
0
        for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
300
0
            aiTexture *tex = scene->mTextures[i];
301
0
            bool compressed = (tex->mHeight == 0);
302
303
            // mesh header
304
0
            std::string texName = "unknown";
305
0
            if (tex->mFilename.length != 0u) {
306
0
                texName = tex->mFilename.data;
307
0
            }
308
0
            ioprintf(io, "\t<Texture name=\"%s\" width=\"%u\" height=\"%u\" compressed=\"%s\"> \n", texName.c_str(),
309
0
                    (compressed ? -1 : tex->mWidth), (compressed ? -1 : tex->mHeight),
310
0
                    (compressed ? "true" : "false"));
311
312
0
            if (compressed) {
313
0
                ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth);
314
315
0
                if (!shortened) {
316
0
                    for (unsigned int n = 0; n < tex->mWidth; ++n) {
317
0
                        ioprintf(io, "\t\t\t%2x", reinterpret_cast<uint8_t *>(tex->pcData)[n]);
318
0
                        if (n && !(n % 50)) {
319
0
                            ioprintf(io, "\n");
320
0
                        }
321
0
                    }
322
0
                }
323
0
            } else if (!shortened) {
324
0
                ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth * tex->mHeight * 4);
325
326
                // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1;
327
0
                for (unsigned int y = 0; y < tex->mHeight; ++y) {
328
0
                    for (unsigned int x = 0; x < tex->mWidth; ++x) {
329
0
                        aiTexel *tx = tex->pcData + y * tex->mWidth + x;
330
0
                        unsigned int r = tx->r, g = tx->g, b = tx->b, a = tx->a;
331
0
                        ioprintf(io, "\t\t\t%2x %2x %2x %2x", r, g, b, a);
332
333
                        // group by four for readability
334
0
                        if (0 == (x + y * tex->mWidth) % 4) {
335
0
                            ioprintf(io, "\n");
336
0
                        }
337
0
                    }
338
0
                }
339
0
            }
340
0
            ioprintf(io, "\t\t</Data>\n\t</Texture>\n");
341
0
        }
342
0
        ioprintf(io, "</TextureList>\n");
343
0
    }
344
345
    // write materials
346
0
    if (scene->mNumMaterials) {
347
0
        ioprintf(io, "<MaterialList num=\"%u\">\n", scene->mNumMaterials);
348
0
        for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
349
0
            const aiMaterial *mat = scene->mMaterials[i];
350
351
0
            ioprintf(io, "\t<Material>\n");
352
0
            ioprintf(io, "\t\t<MatPropertyList  num=\"%u\">\n", mat->mNumProperties);
353
0
            for (unsigned int n = 0; n < mat->mNumProperties; ++n) {
354
355
0
                const aiMaterialProperty *prop = mat->mProperties[n];
356
0
                auto sz = "";
357
0
                if (prop->mType == aiPTI_Float) {
358
0
                    sz = "float";
359
0
                } else if (prop->mType == aiPTI_Integer) {
360
0
                    sz = "integer";
361
0
                } else if (prop->mType == aiPTI_String) {
362
0
                    sz = "string";
363
0
                } else if (prop->mType == aiPTI_Buffer) {
364
0
                    sz = "binary_buffer";
365
0
                }
366
367
0
                ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
368
0
                        prop->mKey.data, sz,
369
0
                        ::aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
370
371
0
                if (prop->mType == aiPTI_Float) {
372
0
                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
373
0
                            static_cast<int>(prop->mDataLength / sizeof(float)));
374
375
0
                    for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(float); ++pp) {
376
0
                        ioprintf(io, "%f ", *((float *)(prop->mData + pp * sizeof(float))));
377
0
                    }
378
0
                } else if (prop->mType == aiPTI_Integer) {
379
0
                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
380
0
                            static_cast<int>(prop->mDataLength / sizeof(int)));
381
382
0
                    for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(int); ++pp) {
383
0
                        ioprintf(io, "%i ", *((int *)(prop->mData + pp * sizeof(int))));
384
0
                    }
385
0
                } else if (prop->mType == aiPTI_Buffer) {
386
0
                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
387
0
                            static_cast<int>(prop->mDataLength));
388
389
0
                    for (unsigned int pp = 0; pp < prop->mDataLength; ++pp) {
390
0
                        ioprintf(io, "%2x ", prop->mData[pp]);
391
0
                        if (pp && 0 == pp % 30) {
392
0
                            ioprintf(io, "\n\t\t\t\t");
393
0
                        }
394
0
                    }
395
0
                } else if (prop->mType == aiPTI_String) {
396
0
                    ioprintf(io, ">\n\t\t\t\t\"%s\"", encodeXML(prop->mData + 4).c_str() /* skip length */);
397
0
                }
398
0
                ioprintf(io, "\n\t\t\t</MatProperty>\n");
399
0
            }
400
0
            ioprintf(io, "\t\t</MatPropertyList>\n");
401
0
            ioprintf(io, "\t</Material>\n");
402
0
        }
403
0
        ioprintf(io, "</MaterialList>\n");
404
0
    }
405
406
    // write animations
407
0
    if (scene->mNumAnimations) {
408
0
        ioprintf(io, "<AnimationList num=\"%u\">\n", scene->mNumAnimations);
409
0
        for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
410
0
            aiAnimation *anim = scene->mAnimations[i];
411
412
            // anim header
413
0
            ConvertName(name, anim->mName);
414
0
            ioprintf(io, "\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
415
0
                    name.data, anim->mDuration, anim->mTicksPerSecond);
416
417
            // write bone animation channels
418
0
            if (anim->mNumChannels) {
419
0
                ioprintf(io, "\t\t<NodeAnimList num=\"%u\">\n", anim->mNumChannels);
420
0
                for (unsigned int n = 0; n < anim->mNumChannels; ++n) {
421
0
                    aiNodeAnim *nd = anim->mChannels[n];
422
423
                    // node anim header
424
0
                    ConvertName(name, nd->mNodeName);
425
0
                    ioprintf(io, "\t\t\t<NodeAnim node=\"%s\">\n", name.data);
426
427
0
                    if (!shortened) {
428
                        // write position keys
429
0
                        if (nd->mNumPositionKeys) {
430
0
                            ioprintf(io, "\t\t\t\t<PositionKeyList num=\"%u\">\n", nd->mNumPositionKeys);
431
0
                            for (unsigned int a = 0; a < nd->mNumPositionKeys; ++a) {
432
0
                                aiVectorKey *vc = nd->mPositionKeys + a;
433
0
                                ioprintf(io, "\t\t\t\t\t<PositionKey time=\"%e\">\n"
434
0
                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
435
0
                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
436
0
                            }
437
0
                            ioprintf(io, "\t\t\t\t</PositionKeyList>\n");
438
0
                        }
439
440
                        // write scaling keys
441
0
                        if (nd->mNumScalingKeys) {
442
0
                            ioprintf(io, "\t\t\t\t<ScalingKeyList num=\"%u\">\n", nd->mNumScalingKeys);
443
0
                            for (unsigned int a = 0; a < nd->mNumScalingKeys; ++a) {
444
0
                                aiVectorKey *vc = nd->mScalingKeys + a;
445
0
                                ioprintf(io, "\t\t\t\t\t<ScalingKey time=\"%e\">\n"
446
0
                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
447
0
                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
448
0
                            }
449
0
                            ioprintf(io, "\t\t\t\t</ScalingKeyList>\n");
450
0
                        }
451
452
                        // write rotation keys
453
0
                        if (nd->mNumRotationKeys) {
454
0
                            ioprintf(io, "\t\t\t\t<RotationKeyList num=\"%u\">\n", nd->mNumRotationKeys);
455
0
                            for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) {
456
0
                                aiQuatKey *vc = nd->mRotationKeys + a;
457
0
                                ioprintf(io, "\t\t\t\t\t<RotationKey time=\"%e\">\n"
458
0
                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
459
0
                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z, vc->mValue.w);
460
0
                            }
461
0
                            ioprintf(io, "\t\t\t\t</RotationKeyList>\n");
462
0
                        }
463
0
                    }
464
0
                    ioprintf(io, "\t\t\t</NodeAnim>\n");
465
0
                }
466
0
                ioprintf(io, "\t\t</NodeAnimList>\n");
467
0
            }
468
0
            ioprintf(io, "\t</Animation>\n");
469
0
        }
470
0
        ioprintf(io, "</AnimationList>\n");
471
0
    }
472
473
    // write meshes
474
0
    if (scene->mNumMeshes) {
475
0
        ioprintf(io, "<MeshList num=\"%u\">\n", scene->mNumMeshes);
476
0
        for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
477
0
            aiMesh *mesh = scene->mMeshes[i];
478
            // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1;
479
480
            // mesh header
481
0
            ioprintf(io, "\t<Mesh types=\"%s %s %s %s\" material_index=\"%u\">\n",
482
0
                    (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""),
483
0
                    (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""),
484
0
                    (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
485
0
                    (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""),
486
0
                    mesh->mMaterialIndex);
487
488
            // bones
489
0
            if (mesh->mNumBones) {
490
0
                ioprintf(io, "\t\t<BoneList num=\"%u\">\n", mesh->mNumBones);
491
492
0
                for (unsigned int n = 0; n < mesh->mNumBones; ++n) {
493
0
                    aiBone *bone = mesh->mBones[n];
494
495
0
                    ConvertName(name, bone->mName);
496
                    // bone header
497
0
                    ioprintf(io, "\t\t\t<Bone name=\"%s\">\n"
498
0
                                 "\t\t\t\t<Matrix4> \n"
499
0
                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
500
0
                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
501
0
                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
502
0
                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
503
0
                                 "\t\t\t\t</Matrix4> \n",
504
0
                            name.data,
505
0
                            bone->mOffsetMatrix.a1, bone->mOffsetMatrix.a2, bone->mOffsetMatrix.a3, bone->mOffsetMatrix.a4,
506
0
                            bone->mOffsetMatrix.b1, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.b4,
507
0
                            bone->mOffsetMatrix.c1, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.c4,
508
0
                            bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3, bone->mOffsetMatrix.d4);
509
510
0
                    if (!shortened && bone->mNumWeights) {
511
0
                        ioprintf(io, "\t\t\t\t<WeightList num=\"%u\">\n", bone->mNumWeights);
512
513
                        // bone weights
514
0
                        for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
515
0
                            aiVertexWeight *wght = bone->mWeights + a;
516
517
0
                            ioprintf(io, "\t\t\t\t\t<Weight index=\"%u\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
518
0
                                    wght->mVertexId, wght->mWeight);
519
0
                        }
520
0
                        ioprintf(io, "\t\t\t\t</WeightList>\n");
521
0
                    }
522
0
                    ioprintf(io, "\t\t\t</Bone>\n");
523
0
                }
524
0
                ioprintf(io, "\t\t</BoneList>\n");
525
0
            }
526
527
            // faces
528
0
            if (!shortened && mesh->mNumFaces) {
529
0
                ioprintf(io, "\t\t<FaceList num=\"%u\">\n", mesh->mNumFaces);
530
0
                for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
531
0
                    aiFace &f = mesh->mFaces[n];
532
0
                    ioprintf(io, "\t\t\t<Face num=\"%u\">\n"
533
0
                                 "\t\t\t\t",
534
0
                            f.mNumIndices);
535
536
0
                    for (unsigned int j = 0; j < f.mNumIndices; ++j)
537
0
                        ioprintf(io, "%u ", f.mIndices[j]);
538
539
0
                    ioprintf(io, "\n\t\t\t</Face>\n");
540
0
                }
541
0
                ioprintf(io, "\t\t</FaceList>\n");
542
0
            }
543
544
            // vertex positions
545
0
            if (mesh->HasPositions()) {
546
0
                ioprintf(io, "\t\t<Positions num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
547
0
                if (!shortened) {
548
0
                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
549
0
                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
550
0
                                mesh->mVertices[n].x,
551
0
                                mesh->mVertices[n].y,
552
0
                                mesh->mVertices[n].z);
553
0
                    }
554
0
                }
555
0
                ioprintf(io, "\t\t</Positions>\n");
556
0
            }
557
558
            // vertex normals
559
0
            if (mesh->HasNormals()) {
560
0
                ioprintf(io, "\t\t<Normals num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
561
0
                if (!shortened) {
562
0
                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
563
0
                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
564
0
                                mesh->mNormals[n].x,
565
0
                                mesh->mNormals[n].y,
566
0
                                mesh->mNormals[n].z);
567
0
                    }
568
0
                }
569
0
                ioprintf(io, "\t\t</Normals>\n");
570
0
            }
571
572
            // vertex tangents and bitangents
573
0
            if (mesh->HasTangentsAndBitangents()) {
574
0
                ioprintf(io, "\t\t<Tangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
575
0
                if (!shortened) {
576
0
                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
577
0
                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
578
0
                                mesh->mTangents[n].x,
579
0
                                mesh->mTangents[n].y,
580
0
                                mesh->mTangents[n].z);
581
0
                    }
582
0
                }
583
0
                ioprintf(io, "\t\t</Tangents>\n");
584
585
0
                ioprintf(io, "\t\t<Bitangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
586
0
                if (!shortened) {
587
0
                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
588
0
                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
589
0
                                mesh->mBitangents[n].x,
590
0
                                mesh->mBitangents[n].y,
591
0
                                mesh->mBitangents[n].z);
592
0
                    }
593
0
                }
594
0
                ioprintf(io, "\t\t</Bitangents>\n");
595
0
            }
596
597
            // texture coordinates
598
0
            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
599
0
                if (!mesh->mTextureCoords[a])
600
0
                    break;
601
602
0
                ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" name=\"%s\" num_components=\"%u\"> \n",
603
0
                         mesh->mNumVertices,
604
0
                         a,
605
0
                         (mesh->HasTextureCoordsName(a) ? mesh->GetTextureCoordsName(a)->C_Str() : ""),
606
0
                         mesh->mNumUVComponents[a]);
607
608
0
                if (!shortened) {
609
0
                    if (mesh->mNumUVComponents[a] == 3) {
610
0
                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
611
0
                            ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
612
0
                                    mesh->mTextureCoords[a][n].x,
613
0
                                    mesh->mTextureCoords[a][n].y,
614
0
                                    mesh->mTextureCoords[a][n].z);
615
0
                        }
616
0
                    } else {
617
0
                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
618
0
                            ioprintf(io, "\t\t%0 8f %0 8f\n",
619
0
                                    mesh->mTextureCoords[a][n].x,
620
0
                                    mesh->mTextureCoords[a][n].y);
621
0
                        }
622
0
                    }
623
0
                }
624
0
                ioprintf(io, "\t\t</TextureCoords>\n");
625
0
            }
626
627
            // vertex colors
628
0
            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
629
0
                if (!mesh->mColors[a])
630
0
                    break;
631
0
                ioprintf(io, "\t\t<Colors num=\"%u\" set=\"%u\" num_components=\"4\"> \n", mesh->mNumVertices, a);
632
0
                if (!shortened) {
633
0
                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
634
0
                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f %0 8f\n",
635
0
                                mesh->mColors[a][n].r,
636
0
                                mesh->mColors[a][n].g,
637
0
                                mesh->mColors[a][n].b,
638
0
                                mesh->mColors[a][n].a);
639
0
                    }
640
0
                }
641
0
                ioprintf(io, "\t\t</Colors>\n");
642
0
            }
643
0
            ioprintf(io, "\t</Mesh>\n");
644
0
        }
645
0
        ioprintf(io, "</MeshList>\n");
646
0
    }
647
0
    ioprintf(io, "</Scene>\n</ASSIMP>");
648
0
}
649
650
} // end of namespace AssxmlFileWriter
651
652
void DumpSceneToAssxml(
653
        const char *pFile, const char *cmd, IOSystem *pIOSystem,
654
0
        const aiScene *pScene, bool shortened) {
655
0
    std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt"));
656
0
    if (!file) {
657
0
        throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
658
0
    }
659
660
0
    AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened);
661
0
}
662
663
} // end of namespace Assimp