vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/ColladaExporter.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,609 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +#include "AssimpPCH.h" 1.45 + 1.46 +#ifndef ASSIMP_BUILD_NO_EXPORT 1.47 +#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER 1.48 +#include "ColladaExporter.h" 1.49 + 1.50 +using namespace Assimp; 1.51 + 1.52 +namespace Assimp 1.53 +{ 1.54 + 1.55 +// ------------------------------------------------------------------------------------------------ 1.56 +// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp 1.57 +void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene) 1.58 +{ 1.59 + // invoke the exporter 1.60 + ColladaExporter iDoTheExportThing( pScene); 1.61 + 1.62 + // we're still here - export successfully completed. Write result to the given IOSYstem 1.63 + boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt")); 1.64 + if(outfile == NULL) { 1.65 + throw DeadlyExportError("could not open output .dae file: " + std::string(pFile)); 1.66 + } 1.67 + 1.68 + // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy. 1.69 + outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1); 1.70 +} 1.71 + 1.72 +} // end of namespace Assimp 1.73 + 1.74 + 1.75 +// ------------------------------------------------------------------------------------------------ 1.76 +// Constructor for a specific scene to export 1.77 +ColladaExporter::ColladaExporter( const aiScene* pScene) 1.78 +{ 1.79 + // make sure that all formatting happens using the standard, C locale and not the user's current locale 1.80 + mOutput.imbue( std::locale("C") ); 1.81 + 1.82 + mScene = pScene; 1.83 + 1.84 + // set up strings 1.85 + endstr = "\n"; 1.86 + 1.87 + // start writing 1.88 + WriteFile(); 1.89 +} 1.90 + 1.91 +// ------------------------------------------------------------------------------------------------ 1.92 +// Starts writing the contents 1.93 +void ColladaExporter::WriteFile() 1.94 +{ 1.95 + // write the DTD 1.96 + mOutput << "<?xml version=\"1.0\"?>" << endstr; 1.97 + // COLLADA element start 1.98 + mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr; 1.99 + PushTag(); 1.100 + 1.101 + WriteHeader(); 1.102 + 1.103 + WriteMaterials(); 1.104 + WriteGeometryLibrary(); 1.105 + 1.106 + WriteSceneLibrary(); 1.107 + 1.108 + // useless Collada fu at the end, just in case we haven't had enough indirections, yet. 1.109 + mOutput << startstr << "<scene>" << endstr; 1.110 + PushTag(); 1.111 + mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr; 1.112 + PopTag(); 1.113 + mOutput << startstr << "</scene>" << endstr; 1.114 + PopTag(); 1.115 + mOutput << "</COLLADA>" << endstr; 1.116 +} 1.117 + 1.118 +// ------------------------------------------------------------------------------------------------ 1.119 +// Writes the asset header 1.120 +void ColladaExporter::WriteHeader() 1.121 +{ 1.122 + // Dummy stuff. Nobody actually cares for it anyways 1.123 + mOutput << startstr << "<asset>" << endstr; 1.124 + PushTag(); 1.125 + mOutput << startstr << "<contributor>" << endstr; 1.126 + PushTag(); 1.127 + mOutput << startstr << "<author>Someone</author>" << endstr; 1.128 + mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr; 1.129 + PopTag(); 1.130 + mOutput << startstr << "</contributor>" << endstr; 1.131 + mOutput << startstr << "<created>2000-01-01T23:59:59</created>" << endstr; 1.132 + mOutput << startstr << "<modified>2000-01-01T23:59:59</modified>" << endstr; 1.133 + mOutput << startstr << "<unit name=\"centimeter\" meter=\"0.01\" />" << endstr; 1.134 + mOutput << startstr << "<up_axis>Y_UP</up_axis>" << endstr; 1.135 + PopTag(); 1.136 + mOutput << startstr << "</asset>" << endstr; 1.137 +} 1.138 + 1.139 +// ------------------------------------------------------------------------------------------------ 1.140 +// Reads a single surface entry from the given material keys 1.141 +void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) 1.142 +{ 1.143 + if( pSrcMat->GetTextureCount( pTexture) > 0 ) 1.144 + { 1.145 + aiString texfile; 1.146 + unsigned int uvChannel = 0; 1.147 + pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel); 1.148 + poSurface.texture = texfile.C_Str(); 1.149 + poSurface.channel = uvChannel; 1.150 + } else 1.151 + { 1.152 + if( pKey ) 1.153 + pSrcMat->Get( pKey, pType, pIndex, poSurface.color); 1.154 + } 1.155 +} 1.156 + 1.157 +// ------------------------------------------------------------------------------------------------ 1.158 +// Writes an image entry for the given surface 1.159 +void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) 1.160 +{ 1.161 + if( !pSurface.texture.empty() ) 1.162 + { 1.163 + mOutput << startstr << "<image id=\"" << pNameAdd << "\">" << endstr; 1.164 + PushTag(); 1.165 + mOutput << startstr << "<init_from>"; 1.166 + for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) 1.167 + { 1.168 + if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) 1.169 + mOutput << *it; 1.170 + else 1.171 + mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; 1.172 + } 1.173 + mOutput << "</init_from>" << endstr; 1.174 + PopTag(); 1.175 + mOutput << startstr << "</image>" << endstr; 1.176 + } 1.177 +} 1.178 + 1.179 +// ------------------------------------------------------------------------------------------------ 1.180 +// Writes a color-or-texture entry into an effect definition 1.181 +void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName) 1.182 +{ 1.183 + mOutput << startstr << "<" << pTypeName << ">" << endstr; 1.184 + PushTag(); 1.185 + if( pSurface.texture.empty() ) 1.186 + { 1.187 + mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr; 1.188 + } else 1.189 + { 1.190 + mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr; 1.191 + } 1.192 + PopTag(); 1.193 + mOutput << startstr << "</" << pTypeName << ">" << endstr; 1.194 +} 1.195 + 1.196 +// ------------------------------------------------------------------------------------------------ 1.197 +// Writes the two parameters necessary for referencing a texture in an effect entry 1.198 +void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName) 1.199 +{ 1.200 + // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture 1.201 + if( !pSurface.texture.empty() ) 1.202 + { 1.203 + mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-surface\">" << endstr; 1.204 + PushTag(); 1.205 + mOutput << startstr << "<surface type=\"2D\">" << endstr; 1.206 + PushTag(); 1.207 + mOutput << startstr << "<init_from>" << pMatName << "-" << pTypeName << "-image</init_from>" << endstr; 1.208 + PopTag(); 1.209 + mOutput << startstr << "</surface>" << endstr; 1.210 + PopTag(); 1.211 + mOutput << startstr << "</newparam>" << endstr; 1.212 + 1.213 + mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-sampler\">" << endstr; 1.214 + PushTag(); 1.215 + mOutput << startstr << "<sampler2D>" << endstr; 1.216 + PushTag(); 1.217 + mOutput << startstr << "<source>" << pMatName << "-" << pTypeName << "-surface</source>" << endstr; 1.218 + PopTag(); 1.219 + mOutput << startstr << "</sampler2D>" << endstr; 1.220 + PopTag(); 1.221 + mOutput << startstr << "</newparam>" << endstr; 1.222 + } 1.223 +} 1.224 + 1.225 +// ------------------------------------------------------------------------------------------------ 1.226 +// Writes the material setup 1.227 +void ColladaExporter::WriteMaterials() 1.228 +{ 1.229 + materials.resize( mScene->mNumMaterials); 1.230 + 1.231 + /// collect all materials from the scene 1.232 + size_t numTextures = 0; 1.233 + for( size_t a = 0; a < mScene->mNumMaterials; ++a ) 1.234 + { 1.235 + const aiMaterial* mat = mScene->mMaterials[a]; 1.236 + 1.237 + aiString name; 1.238 + if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) 1.239 + name = "mat"; 1.240 + materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str(); 1.241 + for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) 1.242 + if( !isalnum( *it) ) 1.243 + *it = '_'; 1.244 + 1.245 + ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); 1.246 + if( !materials[a].ambient.texture.empty() ) numTextures++; 1.247 + ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); 1.248 + if( !materials[a].diffuse.texture.empty() ) numTextures++; 1.249 + ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); 1.250 + if( !materials[a].specular.texture.empty() ) numTextures++; 1.251 + ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); 1.252 + if( !materials[a].emissive.texture.empty() ) numTextures++; 1.253 + ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); 1.254 + if( !materials[a].reflective.texture.empty() ) numTextures++; 1.255 + ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); 1.256 + if( !materials[a].normal.texture.empty() ) numTextures++; 1.257 + 1.258 + mat->Get( AI_MATKEY_SHININESS, materials[a].shininess); 1.259 + } 1.260 + 1.261 + // output textures if present 1.262 + if( numTextures > 0 ) 1.263 + { 1.264 + mOutput << startstr << "<library_images>" << endstr; 1.265 + PushTag(); 1.266 + for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) 1.267 + { 1.268 + const Material& mat = *it; 1.269 + WriteImageEntry( mat.ambient, mat.name + "-ambient-image"); 1.270 + WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image"); 1.271 + WriteImageEntry( mat.specular, mat.name + "-specular-image"); 1.272 + WriteImageEntry( mat.emissive, mat.name + "-emissive-image"); 1.273 + WriteImageEntry( mat.reflective, mat.name + "-reflective-image"); 1.274 + WriteImageEntry( mat.normal, mat.name + "-normal-image"); 1.275 + } 1.276 + PopTag(); 1.277 + mOutput << startstr << "</library_images>" << endstr; 1.278 + } 1.279 + 1.280 + // output effects - those are the actual carriers of information 1.281 + if( !materials.empty() ) 1.282 + { 1.283 + mOutput << startstr << "<library_effects>" << endstr; 1.284 + PushTag(); 1.285 + for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) 1.286 + { 1.287 + const Material& mat = *it; 1.288 + // this is so ridiculous it must be right 1.289 + mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr; 1.290 + PushTag(); 1.291 + mOutput << startstr << "<profile_COMMON>" << endstr; 1.292 + PushTag(); 1.293 + 1.294 + // write sampler- and surface params for the texture entries 1.295 + WriteTextureParamEntry( mat.emissive, "emissive", mat.name); 1.296 + WriteTextureParamEntry( mat.ambient, "ambient", mat.name); 1.297 + WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name); 1.298 + WriteTextureParamEntry( mat.specular, "specular", mat.name); 1.299 + WriteTextureParamEntry( mat.reflective, "reflective", mat.name); 1.300 + 1.301 + mOutput << startstr << "<technique sid=\"standard\">" << endstr; 1.302 + PushTag(); 1.303 + mOutput << startstr << "<phong>" << endstr; 1.304 + PushTag(); 1.305 + 1.306 + WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emissive-sampler"); 1.307 + WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler"); 1.308 + WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); 1.309 + WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler"); 1.310 + 1.311 + mOutput << startstr << "<shininess>" << endstr; 1.312 + PushTag(); 1.313 + mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr; 1.314 + PopTag(); 1.315 + mOutput << startstr << "</shininess>" << endstr; 1.316 + 1.317 + WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler"); 1.318 + 1.319 + // deactivated because the Collada spec PHONG model does not allow other textures. 1.320 + // if( !mat.normal.texture.empty() ) 1.321 + // WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler"); 1.322 + 1.323 + 1.324 + PopTag(); 1.325 + mOutput << startstr << "</phong>" << endstr; 1.326 + PopTag(); 1.327 + mOutput << startstr << "</technique>" << endstr; 1.328 + PopTag(); 1.329 + mOutput << startstr << "</profile_COMMON>" << endstr; 1.330 + PopTag(); 1.331 + mOutput << startstr << "</effect>" << endstr; 1.332 + } 1.333 + PopTag(); 1.334 + mOutput << startstr << "</library_effects>" << endstr; 1.335 + 1.336 + // write materials - they're just effect references 1.337 + mOutput << startstr << "<library_materials>" << endstr; 1.338 + PushTag(); 1.339 + for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) 1.340 + { 1.341 + const Material& mat = *it; 1.342 + mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr; 1.343 + PushTag(); 1.344 + mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr; 1.345 + PopTag(); 1.346 + mOutput << startstr << "</material>" << endstr; 1.347 + } 1.348 + PopTag(); 1.349 + mOutput << startstr << "</library_materials>" << endstr; 1.350 + } 1.351 +} 1.352 + 1.353 +// ------------------------------------------------------------------------------------------------ 1.354 +// Writes the geometry library 1.355 +void ColladaExporter::WriteGeometryLibrary() 1.356 +{ 1.357 + mOutput << startstr << "<library_geometries>" << endstr; 1.358 + PushTag(); 1.359 + 1.360 + for( size_t a = 0; a < mScene->mNumMeshes; ++a) 1.361 + WriteGeometry( a); 1.362 + 1.363 + PopTag(); 1.364 + mOutput << startstr << "</library_geometries>" << endstr; 1.365 +} 1.366 + 1.367 +// ------------------------------------------------------------------------------------------------ 1.368 +// Writes the given mesh 1.369 +void ColladaExporter::WriteGeometry( size_t pIndex) 1.370 +{ 1.371 + const aiMesh* mesh = mScene->mMeshes[pIndex]; 1.372 + std::string idstr = GetMeshId( pIndex); 1.373 + 1.374 + if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) 1.375 + return; 1.376 + 1.377 + // opening tag 1.378 + mOutput << startstr << "<geometry id=\"" << idstr << "\" name=\"" << idstr << "_name\" >" << endstr; 1.379 + PushTag(); 1.380 + 1.381 + mOutput << startstr << "<mesh>" << endstr; 1.382 + PushTag(); 1.383 + 1.384 + // Positions 1.385 + WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices); 1.386 + // Normals, if any 1.387 + if( mesh->HasNormals() ) 1.388 + WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices); 1.389 + 1.390 + // texture coords 1.391 + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) 1.392 + { 1.393 + if( mesh->HasTextureCoords( a) ) 1.394 + { 1.395 + WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, 1.396 + (float*) mesh->mTextureCoords[a], mesh->mNumVertices); 1.397 + } 1.398 + } 1.399 + 1.400 + // vertex colors 1.401 + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) 1.402 + { 1.403 + if( mesh->HasVertexColors( a) ) 1.404 + WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices); 1.405 + } 1.406 + 1.407 + // assemble vertex structure 1.408 + mOutput << startstr << "<vertices id=\"" << idstr << "-vertices" << "\">" << endstr; 1.409 + PushTag(); 1.410 + mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstr << "-positions\" />" << endstr; 1.411 + if( mesh->HasNormals() ) 1.412 + mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstr << "-normals\" />" << endstr; 1.413 + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) 1.414 + { 1.415 + if( mesh->HasTextureCoords( a) ) 1.416 + mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstr << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr; 1.417 + } 1.418 + for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) 1.419 + { 1.420 + if( mesh->HasVertexColors( a) ) 1.421 + mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstr << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr; 1.422 + } 1.423 + 1.424 + PopTag(); 1.425 + mOutput << startstr << "</vertices>" << endstr; 1.426 + 1.427 + // write face setup 1.428 + mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr; 1.429 + PushTag(); 1.430 + mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr; 1.431 + 1.432 + mOutput << startstr << "<vcount>"; 1.433 + for( size_t a = 0; a < mesh->mNumFaces; ++a ) 1.434 + mOutput << mesh->mFaces[a].mNumIndices << " "; 1.435 + mOutput << "</vcount>" << endstr; 1.436 + 1.437 + mOutput << startstr << "<p>"; 1.438 + for( size_t a = 0; a < mesh->mNumFaces; ++a ) 1.439 + { 1.440 + const aiFace& face = mesh->mFaces[a]; 1.441 + for( size_t b = 0; b < face.mNumIndices; ++b ) 1.442 + mOutput << face.mIndices[b] << " "; 1.443 + } 1.444 + mOutput << "</p>" << endstr; 1.445 + PopTag(); 1.446 + mOutput << startstr << "</polylist>" << endstr; 1.447 + 1.448 + // closing tags 1.449 + PopTag(); 1.450 + mOutput << startstr << "</mesh>" << endstr; 1.451 + PopTag(); 1.452 + mOutput << startstr << "</geometry>" << endstr; 1.453 +} 1.454 + 1.455 +// ------------------------------------------------------------------------------------------------ 1.456 +// Writes a float array of the given type 1.457 +void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount) 1.458 +{ 1.459 + size_t floatsPerElement = 0; 1.460 + switch( pType ) 1.461 + { 1.462 + case FloatType_Vector: floatsPerElement = 3; break; 1.463 + case FloatType_TexCoord2: floatsPerElement = 2; break; 1.464 + case FloatType_TexCoord3: floatsPerElement = 3; break; 1.465 + case FloatType_Color: floatsPerElement = 3; break; 1.466 + default: 1.467 + return; 1.468 + } 1.469 + 1.470 + std::string arrayId = pIdString + "-array"; 1.471 + 1.472 + mOutput << startstr << "<source id=\"" << pIdString << "\" name=\"" << pIdString << "\">" << endstr; 1.473 + PushTag(); 1.474 + 1.475 + // source array 1.476 + mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> "; 1.477 + PushTag(); 1.478 + 1.479 + if( pType == FloatType_TexCoord2 ) 1.480 + { 1.481 + for( size_t a = 0; a < pElementCount; ++a ) 1.482 + { 1.483 + mOutput << pData[a*3+0] << " "; 1.484 + mOutput << pData[a*3+1] << " "; 1.485 + } 1.486 + } 1.487 + else if( pType == FloatType_Color ) 1.488 + { 1.489 + for( size_t a = 0; a < pElementCount; ++a ) 1.490 + { 1.491 + mOutput << pData[a*4+0] << " "; 1.492 + mOutput << pData[a*4+1] << " "; 1.493 + mOutput << pData[a*4+2] << " "; 1.494 + } 1.495 + } 1.496 + else 1.497 + { 1.498 + for( size_t a = 0; a < pElementCount * floatsPerElement; ++a ) 1.499 + mOutput << pData[a] << " "; 1.500 + } 1.501 + mOutput << "</float_array>" << endstr; 1.502 + PopTag(); 1.503 + 1.504 + // the usual Collada fun. Let's bloat it even more! 1.505 + mOutput << startstr << "<technique_common>" << endstr; 1.506 + PushTag(); 1.507 + mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr; 1.508 + PushTag(); 1.509 + 1.510 + switch( pType ) 1.511 + { 1.512 + case FloatType_Vector: 1.513 + mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr; 1.514 + mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr; 1.515 + mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr; 1.516 + break; 1.517 + 1.518 + case FloatType_TexCoord2: 1.519 + mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr; 1.520 + mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr; 1.521 + break; 1.522 + 1.523 + case FloatType_TexCoord3: 1.524 + mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr; 1.525 + mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr; 1.526 + mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr; 1.527 + break; 1.528 + 1.529 + case FloatType_Color: 1.530 + mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr; 1.531 + mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr; 1.532 + mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr; 1.533 + break; 1.534 + } 1.535 + 1.536 + PopTag(); 1.537 + mOutput << startstr << "</accessor>" << endstr; 1.538 + PopTag(); 1.539 + mOutput << startstr << "</technique_common>" << endstr; 1.540 + PopTag(); 1.541 + mOutput << startstr << "</source>" << endstr; 1.542 +} 1.543 + 1.544 +// ------------------------------------------------------------------------------------------------ 1.545 +// Writes the scene library 1.546 +void ColladaExporter::WriteSceneLibrary() 1.547 +{ 1.548 + mOutput << startstr << "<library_visual_scenes>" << endstr; 1.549 + PushTag(); 1.550 + mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr; 1.551 + PushTag(); 1.552 + 1.553 + // start recursive write at the root node 1.554 + WriteNode( mScene->mRootNode); 1.555 + 1.556 + PopTag(); 1.557 + mOutput << startstr << "</visual_scene>" << endstr; 1.558 + PopTag(); 1.559 + mOutput << startstr << "</library_visual_scenes>" << endstr; 1.560 +} 1.561 + 1.562 +// ------------------------------------------------------------------------------------------------ 1.563 +// Recursively writes the given node 1.564 +void ColladaExporter::WriteNode( const aiNode* pNode) 1.565 +{ 1.566 + mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr; 1.567 + PushTag(); 1.568 + 1.569 + // write transformation - we can directly put the matrix there 1.570 + // TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards 1.571 + const aiMatrix4x4& mat = pNode->mTransformation; 1.572 + mOutput << startstr << "<matrix>"; 1.573 + mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " "; 1.574 + mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " "; 1.575 + mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " "; 1.576 + mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4; 1.577 + mOutput << "</matrix>" << endstr; 1.578 + 1.579 + // instance every geometry 1.580 + for( size_t a = 0; a < pNode->mNumMeshes; ++a ) 1.581 + { 1.582 + const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]]; 1.583 + // do not instanciate mesh if empty. I wonder how this could happen 1.584 + if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) 1.585 + continue; 1.586 + 1.587 + mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr; 1.588 + PushTag(); 1.589 + mOutput << startstr << "<bind_material>" << endstr; 1.590 + PushTag(); 1.591 + mOutput << startstr << "<technique_common>" << endstr; 1.592 + PushTag(); 1.593 + mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr; 1.594 + PopTag(); 1.595 + mOutput << startstr << "</technique_common>" << endstr; 1.596 + PopTag(); 1.597 + mOutput << startstr << "</bind_material>" << endstr; 1.598 + PopTag(); 1.599 + mOutput << startstr << "</instance_geometry>" << endstr; 1.600 + } 1.601 + 1.602 + // recurse into subnodes 1.603 + for( size_t a = 0; a < pNode->mNumChildren; ++a ) 1.604 + WriteNode( pNode->mChildren[a]); 1.605 + 1.606 + PopTag(); 1.607 + mOutput << startstr << "</node>" << endstr; 1.608 +} 1.609 + 1.610 +#endif 1.611 +#endif 1.612 +