vrshoot
view libs/assimp/ColladaExporter.cpp @ 2:334d17aed7de
visual studio project files
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Feb 2014 18:36:38 +0200 |
parents | |
children |
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
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:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
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.
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.
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.
38 ----------------------------------------------------------------------
39 */
41 #include "AssimpPCH.h"
43 #ifndef ASSIMP_BUILD_NO_EXPORT
44 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
45 #include "ColladaExporter.h"
47 using namespace Assimp;
49 namespace Assimp
50 {
52 // ------------------------------------------------------------------------------------------------
53 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
54 void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
55 {
56 // invoke the exporter
57 ColladaExporter iDoTheExportThing( pScene);
59 // we're still here - export successfully completed. Write result to the given IOSYstem
60 boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
61 if(outfile == NULL) {
62 throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
63 }
65 // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
66 outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
67 }
69 } // end of namespace Assimp
72 // ------------------------------------------------------------------------------------------------
73 // Constructor for a specific scene to export
74 ColladaExporter::ColladaExporter( const aiScene* pScene)
75 {
76 // make sure that all formatting happens using the standard, C locale and not the user's current locale
77 mOutput.imbue( std::locale("C") );
79 mScene = pScene;
81 // set up strings
82 endstr = "\n";
84 // start writing
85 WriteFile();
86 }
88 // ------------------------------------------------------------------------------------------------
89 // Starts writing the contents
90 void ColladaExporter::WriteFile()
91 {
92 // write the DTD
93 mOutput << "<?xml version=\"1.0\"?>" << endstr;
94 // COLLADA element start
95 mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
96 PushTag();
98 WriteHeader();
100 WriteMaterials();
101 WriteGeometryLibrary();
103 WriteSceneLibrary();
105 // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
106 mOutput << startstr << "<scene>" << endstr;
107 PushTag();
108 mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr;
109 PopTag();
110 mOutput << startstr << "</scene>" << endstr;
111 PopTag();
112 mOutput << "</COLLADA>" << endstr;
113 }
115 // ------------------------------------------------------------------------------------------------
116 // Writes the asset header
117 void ColladaExporter::WriteHeader()
118 {
119 // Dummy stuff. Nobody actually cares for it anyways
120 mOutput << startstr << "<asset>" << endstr;
121 PushTag();
122 mOutput << startstr << "<contributor>" << endstr;
123 PushTag();
124 mOutput << startstr << "<author>Someone</author>" << endstr;
125 mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
126 PopTag();
127 mOutput << startstr << "</contributor>" << endstr;
128 mOutput << startstr << "<created>2000-01-01T23:59:59</created>" << endstr;
129 mOutput << startstr << "<modified>2000-01-01T23:59:59</modified>" << endstr;
130 mOutput << startstr << "<unit name=\"centimeter\" meter=\"0.01\" />" << endstr;
131 mOutput << startstr << "<up_axis>Y_UP</up_axis>" << endstr;
132 PopTag();
133 mOutput << startstr << "</asset>" << endstr;
134 }
136 // ------------------------------------------------------------------------------------------------
137 // Reads a single surface entry from the given material keys
138 void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
139 {
140 if( pSrcMat->GetTextureCount( pTexture) > 0 )
141 {
142 aiString texfile;
143 unsigned int uvChannel = 0;
144 pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
145 poSurface.texture = texfile.C_Str();
146 poSurface.channel = uvChannel;
147 } else
148 {
149 if( pKey )
150 pSrcMat->Get( pKey, pType, pIndex, poSurface.color);
151 }
152 }
154 // ------------------------------------------------------------------------------------------------
155 // Writes an image entry for the given surface
156 void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd)
157 {
158 if( !pSurface.texture.empty() )
159 {
160 mOutput << startstr << "<image id=\"" << pNameAdd << "\">" << endstr;
161 PushTag();
162 mOutput << startstr << "<init_from>";
163 for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it )
164 {
165 if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' )
166 mOutput << *it;
167 else
168 mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec;
169 }
170 mOutput << "</init_from>" << endstr;
171 PopTag();
172 mOutput << startstr << "</image>" << endstr;
173 }
174 }
176 // ------------------------------------------------------------------------------------------------
177 // Writes a color-or-texture entry into an effect definition
178 void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
179 {
180 mOutput << startstr << "<" << pTypeName << ">" << endstr;
181 PushTag();
182 if( pSurface.texture.empty() )
183 {
184 mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr;
185 } else
186 {
187 mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
188 }
189 PopTag();
190 mOutput << startstr << "</" << pTypeName << ">" << endstr;
191 }
193 // ------------------------------------------------------------------------------------------------
194 // Writes the two parameters necessary for referencing a texture in an effect entry
195 void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName)
196 {
197 // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
198 if( !pSurface.texture.empty() )
199 {
200 mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-surface\">" << endstr;
201 PushTag();
202 mOutput << startstr << "<surface type=\"2D\">" << endstr;
203 PushTag();
204 mOutput << startstr << "<init_from>" << pMatName << "-" << pTypeName << "-image</init_from>" << endstr;
205 PopTag();
206 mOutput << startstr << "</surface>" << endstr;
207 PopTag();
208 mOutput << startstr << "</newparam>" << endstr;
210 mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-sampler\">" << endstr;
211 PushTag();
212 mOutput << startstr << "<sampler2D>" << endstr;
213 PushTag();
214 mOutput << startstr << "<source>" << pMatName << "-" << pTypeName << "-surface</source>" << endstr;
215 PopTag();
216 mOutput << startstr << "</sampler2D>" << endstr;
217 PopTag();
218 mOutput << startstr << "</newparam>" << endstr;
219 }
220 }
222 // ------------------------------------------------------------------------------------------------
223 // Writes the material setup
224 void ColladaExporter::WriteMaterials()
225 {
226 materials.resize( mScene->mNumMaterials);
228 /// collect all materials from the scene
229 size_t numTextures = 0;
230 for( size_t a = 0; a < mScene->mNumMaterials; ++a )
231 {
232 const aiMaterial* mat = mScene->mMaterials[a];
234 aiString name;
235 if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
236 name = "mat";
237 materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
238 for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it )
239 if( !isalnum( *it) )
240 *it = '_';
242 ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
243 if( !materials[a].ambient.texture.empty() ) numTextures++;
244 ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
245 if( !materials[a].diffuse.texture.empty() ) numTextures++;
246 ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
247 if( !materials[a].specular.texture.empty() ) numTextures++;
248 ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
249 if( !materials[a].emissive.texture.empty() ) numTextures++;
250 ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
251 if( !materials[a].reflective.texture.empty() ) numTextures++;
252 ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
253 if( !materials[a].normal.texture.empty() ) numTextures++;
255 mat->Get( AI_MATKEY_SHININESS, materials[a].shininess);
256 }
258 // output textures if present
259 if( numTextures > 0 )
260 {
261 mOutput << startstr << "<library_images>" << endstr;
262 PushTag();
263 for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
264 {
265 const Material& mat = *it;
266 WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
267 WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
268 WriteImageEntry( mat.specular, mat.name + "-specular-image");
269 WriteImageEntry( mat.emissive, mat.name + "-emissive-image");
270 WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
271 WriteImageEntry( mat.normal, mat.name + "-normal-image");
272 }
273 PopTag();
274 mOutput << startstr << "</library_images>" << endstr;
275 }
277 // output effects - those are the actual carriers of information
278 if( !materials.empty() )
279 {
280 mOutput << startstr << "<library_effects>" << endstr;
281 PushTag();
282 for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
283 {
284 const Material& mat = *it;
285 // this is so ridiculous it must be right
286 mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr;
287 PushTag();
288 mOutput << startstr << "<profile_COMMON>" << endstr;
289 PushTag();
291 // write sampler- and surface params for the texture entries
292 WriteTextureParamEntry( mat.emissive, "emissive", mat.name);
293 WriteTextureParamEntry( mat.ambient, "ambient", mat.name);
294 WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
295 WriteTextureParamEntry( mat.specular, "specular", mat.name);
296 WriteTextureParamEntry( mat.reflective, "reflective", mat.name);
298 mOutput << startstr << "<technique sid=\"standard\">" << endstr;
299 PushTag();
300 mOutput << startstr << "<phong>" << endstr;
301 PushTag();
303 WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emissive-sampler");
304 WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
305 WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
306 WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");
308 mOutput << startstr << "<shininess>" << endstr;
309 PushTag();
310 mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr;
311 PopTag();
312 mOutput << startstr << "</shininess>" << endstr;
314 WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");
316 // deactivated because the Collada spec PHONG model does not allow other textures.
317 // if( !mat.normal.texture.empty() )
318 // WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
321 PopTag();
322 mOutput << startstr << "</phong>" << endstr;
323 PopTag();
324 mOutput << startstr << "</technique>" << endstr;
325 PopTag();
326 mOutput << startstr << "</profile_COMMON>" << endstr;
327 PopTag();
328 mOutput << startstr << "</effect>" << endstr;
329 }
330 PopTag();
331 mOutput << startstr << "</library_effects>" << endstr;
333 // write materials - they're just effect references
334 mOutput << startstr << "<library_materials>" << endstr;
335 PushTag();
336 for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
337 {
338 const Material& mat = *it;
339 mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr;
340 PushTag();
341 mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr;
342 PopTag();
343 mOutput << startstr << "</material>" << endstr;
344 }
345 PopTag();
346 mOutput << startstr << "</library_materials>" << endstr;
347 }
348 }
350 // ------------------------------------------------------------------------------------------------
351 // Writes the geometry library
352 void ColladaExporter::WriteGeometryLibrary()
353 {
354 mOutput << startstr << "<library_geometries>" << endstr;
355 PushTag();
357 for( size_t a = 0; a < mScene->mNumMeshes; ++a)
358 WriteGeometry( a);
360 PopTag();
361 mOutput << startstr << "</library_geometries>" << endstr;
362 }
364 // ------------------------------------------------------------------------------------------------
365 // Writes the given mesh
366 void ColladaExporter::WriteGeometry( size_t pIndex)
367 {
368 const aiMesh* mesh = mScene->mMeshes[pIndex];
369 std::string idstr = GetMeshId( pIndex);
371 if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
372 return;
374 // opening tag
375 mOutput << startstr << "<geometry id=\"" << idstr << "\" name=\"" << idstr << "_name\" >" << endstr;
376 PushTag();
378 mOutput << startstr << "<mesh>" << endstr;
379 PushTag();
381 // Positions
382 WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices);
383 // Normals, if any
384 if( mesh->HasNormals() )
385 WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices);
387 // texture coords
388 for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
389 {
390 if( mesh->HasTextureCoords( a) )
391 {
392 WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
393 (float*) mesh->mTextureCoords[a], mesh->mNumVertices);
394 }
395 }
397 // vertex colors
398 for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
399 {
400 if( mesh->HasVertexColors( a) )
401 WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices);
402 }
404 // assemble vertex structure
405 mOutput << startstr << "<vertices id=\"" << idstr << "-vertices" << "\">" << endstr;
406 PushTag();
407 mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstr << "-positions\" />" << endstr;
408 if( mesh->HasNormals() )
409 mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstr << "-normals\" />" << endstr;
410 for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
411 {
412 if( mesh->HasTextureCoords( a) )
413 mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstr << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
414 }
415 for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
416 {
417 if( mesh->HasVertexColors( a) )
418 mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstr << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
419 }
421 PopTag();
422 mOutput << startstr << "</vertices>" << endstr;
424 // write face setup
425 mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr;
426 PushTag();
427 mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
429 mOutput << startstr << "<vcount>";
430 for( size_t a = 0; a < mesh->mNumFaces; ++a )
431 mOutput << mesh->mFaces[a].mNumIndices << " ";
432 mOutput << "</vcount>" << endstr;
434 mOutput << startstr << "<p>";
435 for( size_t a = 0; a < mesh->mNumFaces; ++a )
436 {
437 const aiFace& face = mesh->mFaces[a];
438 for( size_t b = 0; b < face.mNumIndices; ++b )
439 mOutput << face.mIndices[b] << " ";
440 }
441 mOutput << "</p>" << endstr;
442 PopTag();
443 mOutput << startstr << "</polylist>" << endstr;
445 // closing tags
446 PopTag();
447 mOutput << startstr << "</mesh>" << endstr;
448 PopTag();
449 mOutput << startstr << "</geometry>" << endstr;
450 }
452 // ------------------------------------------------------------------------------------------------
453 // Writes a float array of the given type
454 void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount)
455 {
456 size_t floatsPerElement = 0;
457 switch( pType )
458 {
459 case FloatType_Vector: floatsPerElement = 3; break;
460 case FloatType_TexCoord2: floatsPerElement = 2; break;
461 case FloatType_TexCoord3: floatsPerElement = 3; break;
462 case FloatType_Color: floatsPerElement = 3; break;
463 default:
464 return;
465 }
467 std::string arrayId = pIdString + "-array";
469 mOutput << startstr << "<source id=\"" << pIdString << "\" name=\"" << pIdString << "\">" << endstr;
470 PushTag();
472 // source array
473 mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
474 PushTag();
476 if( pType == FloatType_TexCoord2 )
477 {
478 for( size_t a = 0; a < pElementCount; ++a )
479 {
480 mOutput << pData[a*3+0] << " ";
481 mOutput << pData[a*3+1] << " ";
482 }
483 }
484 else if( pType == FloatType_Color )
485 {
486 for( size_t a = 0; a < pElementCount; ++a )
487 {
488 mOutput << pData[a*4+0] << " ";
489 mOutput << pData[a*4+1] << " ";
490 mOutput << pData[a*4+2] << " ";
491 }
492 }
493 else
494 {
495 for( size_t a = 0; a < pElementCount * floatsPerElement; ++a )
496 mOutput << pData[a] << " ";
497 }
498 mOutput << "</float_array>" << endstr;
499 PopTag();
501 // the usual Collada fun. Let's bloat it even more!
502 mOutput << startstr << "<technique_common>" << endstr;
503 PushTag();
504 mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr;
505 PushTag();
507 switch( pType )
508 {
509 case FloatType_Vector:
510 mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr;
511 mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr;
512 mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr;
513 break;
515 case FloatType_TexCoord2:
516 mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
517 mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
518 break;
520 case FloatType_TexCoord3:
521 mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
522 mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
523 mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr;
524 break;
526 case FloatType_Color:
527 mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr;
528 mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr;
529 mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr;
530 break;
531 }
533 PopTag();
534 mOutput << startstr << "</accessor>" << endstr;
535 PopTag();
536 mOutput << startstr << "</technique_common>" << endstr;
537 PopTag();
538 mOutput << startstr << "</source>" << endstr;
539 }
541 // ------------------------------------------------------------------------------------------------
542 // Writes the scene library
543 void ColladaExporter::WriteSceneLibrary()
544 {
545 mOutput << startstr << "<library_visual_scenes>" << endstr;
546 PushTag();
547 mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr;
548 PushTag();
550 // start recursive write at the root node
551 WriteNode( mScene->mRootNode);
553 PopTag();
554 mOutput << startstr << "</visual_scene>" << endstr;
555 PopTag();
556 mOutput << startstr << "</library_visual_scenes>" << endstr;
557 }
559 // ------------------------------------------------------------------------------------------------
560 // Recursively writes the given node
561 void ColladaExporter::WriteNode( const aiNode* pNode)
562 {
563 mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr;
564 PushTag();
566 // write transformation - we can directly put the matrix there
567 // TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards
568 const aiMatrix4x4& mat = pNode->mTransformation;
569 mOutput << startstr << "<matrix>";
570 mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
571 mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
572 mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
573 mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4;
574 mOutput << "</matrix>" << endstr;
576 // instance every geometry
577 for( size_t a = 0; a < pNode->mNumMeshes; ++a )
578 {
579 const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
580 // do not instanciate mesh if empty. I wonder how this could happen
581 if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
582 continue;
584 mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
585 PushTag();
586 mOutput << startstr << "<bind_material>" << endstr;
587 PushTag();
588 mOutput << startstr << "<technique_common>" << endstr;
589 PushTag();
590 mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
591 PopTag();
592 mOutput << startstr << "</technique_common>" << endstr;
593 PopTag();
594 mOutput << startstr << "</bind_material>" << endstr;
595 PopTag();
596 mOutput << startstr << "</instance_geometry>" << endstr;
597 }
599 // recurse into subnodes
600 for( size_t a = 0; a < pNode->mNumChildren; ++a )
601 WriteNode( pNode->mChildren[a]);
603 PopTag();
604 mOutput << startstr << "</node>" << endstr;
605 }
607 #endif
608 #endif