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("<");break;
102 case '>':
103 out.Append(">");break;
104 case '&':
105 out.Append("&");break;
106 case '\"':
107 out.Append(""");break;
108 case '\'':
109 out.Append("'");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("&"); break;
174 case '\"': buffer.append("""); break;
175 case '\'': buffer.append("'"); break;
176 case '<': buffer.append("<"); break;
177 case '>': buffer.append(">"); 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