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