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("<");break;
91 case '>':
92 out.Append(">");break;
93 case '&':
94 out.Append("&");break;
95 case '\"':
96 out.Append(""");break;
97 case '\'':
98 out.Append("'");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("&"); break;
164 case '\"': buffer.append("""); break;
165 case '\'': buffer.append("'"); break;
166 case '<': buffer.append("<"); break;
167 case '>': buffer.append(">"); 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