1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following 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
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF 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
63using namespace Assimp;
64
65namespace Assimp {
66
67namespace AssxmlExport {
68
69// -----------------------------------------------------------------------------------
70static 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
92static 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
115static 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
164static 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
182static
183void 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
634void 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