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