vrshoot

annotate libs/assimp/ColladaExporter.cpp @ 0:b2f14e535253

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