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