vrshoot

annotate libs/assimp/XFileImporter.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 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41 /** @file XFileImporter.cpp
nuclear@0 42 * @brief Implementation of the XFile importer class
nuclear@0 43 */
nuclear@0 44
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46 #ifndef ASSIMP_BUILD_NO_X_IMPORTER
nuclear@0 47
nuclear@0 48 #include "XFileImporter.h"
nuclear@0 49 #include "XFileParser.h"
nuclear@0 50 #include "ConvertToLHProcess.h"
nuclear@0 51
nuclear@0 52 using namespace Assimp;
nuclear@0 53
nuclear@0 54 static const aiImporterDesc desc = {
nuclear@0 55 "Direct3D XFile Importer",
nuclear@0 56 "",
nuclear@0 57 "",
nuclear@0 58 "",
nuclear@0 59 aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
nuclear@0 60 1,
nuclear@0 61 3,
nuclear@0 62 1,
nuclear@0 63 5,
nuclear@0 64 "x"
nuclear@0 65 };
nuclear@0 66
nuclear@0 67 // ------------------------------------------------------------------------------------------------
nuclear@0 68 // Constructor to be privately used by Importer
nuclear@0 69 XFileImporter::XFileImporter()
nuclear@0 70 {}
nuclear@0 71
nuclear@0 72 // ------------------------------------------------------------------------------------------------
nuclear@0 73 // Destructor, private as well
nuclear@0 74 XFileImporter::~XFileImporter()
nuclear@0 75 {}
nuclear@0 76
nuclear@0 77 // ------------------------------------------------------------------------------------------------
nuclear@0 78 // Returns whether the class can handle the format of the given file.
nuclear@0 79 bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 80 {
nuclear@0 81 std::string extension = GetExtension(pFile);
nuclear@0 82 if(extension == "x") {
nuclear@0 83 return true;
nuclear@0 84 }
nuclear@0 85 if (!extension.length() || checkSig) {
nuclear@0 86 uint32_t token[1];
nuclear@0 87 token[0] = AI_MAKE_MAGIC("xof ");
nuclear@0 88 return CheckMagicToken(pIOHandler,pFile,token,1,0);
nuclear@0 89 }
nuclear@0 90 return false;
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 // ------------------------------------------------------------------------------------------------
nuclear@0 94 // Get file extension list
nuclear@0 95 const aiImporterDesc* XFileImporter::GetInfo () const
nuclear@0 96 {
nuclear@0 97 return &desc;
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 // ------------------------------------------------------------------------------------------------
nuclear@0 101 // Imports the given file into the given scene structure.
nuclear@0 102 void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 103 {
nuclear@0 104 // read file into memory
nuclear@0 105 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
nuclear@0 106 if( file.get() == NULL)
nuclear@0 107 throw DeadlyImportError( "Failed to open file " + pFile + ".");
nuclear@0 108
nuclear@0 109 size_t fileSize = file->FileSize();
nuclear@0 110 if( fileSize < 16)
nuclear@0 111 throw DeadlyImportError( "XFile is too small.");
nuclear@0 112
nuclear@0 113 // in the hope that binary files will never start with a BOM ...
nuclear@0 114 mBuffer.resize( fileSize + 1);
nuclear@0 115 file->Read( &mBuffer.front(), 1, fileSize);
nuclear@0 116 ConvertToUTF8(mBuffer);
nuclear@0 117
nuclear@0 118 // parse the file into a temporary representation
nuclear@0 119 XFileParser parser( mBuffer);
nuclear@0 120
nuclear@0 121 // and create the proper return structures out of it
nuclear@0 122 CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
nuclear@0 123
nuclear@0 124 // if nothing came from it, report it as error
nuclear@0 125 if( !pScene->mRootNode)
nuclear@0 126 throw DeadlyImportError( "XFile is ill-formatted - no content imported.");
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 // ------------------------------------------------------------------------------------------------
nuclear@0 130 // Constructs the return data structure out of the imported data.
nuclear@0 131 void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::Scene* pData)
nuclear@0 132 {
nuclear@0 133 // Read the global materials first so that meshes referring to them can find them later
nuclear@0 134 ConvertMaterials( pScene, pData->mGlobalMaterials);
nuclear@0 135
nuclear@0 136 // copy nodes, extracting meshes and materials on the way
nuclear@0 137 pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode);
nuclear@0 138
nuclear@0 139 // extract animations
nuclear@0 140 CreateAnimations( pScene, pData);
nuclear@0 141
nuclear@0 142 // read the global meshes that were stored outside of any node
nuclear@0 143 if( pData->mGlobalMeshes.size() > 0)
nuclear@0 144 {
nuclear@0 145 // create a root node to hold them if there isn't any, yet
nuclear@0 146 if( pScene->mRootNode == NULL)
nuclear@0 147 {
nuclear@0 148 pScene->mRootNode = new aiNode;
nuclear@0 149 pScene->mRootNode->mName.Set( "$dummy_node");
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 // convert all global meshes and store them in the root node.
nuclear@0 153 // If there was one before, the global meshes now suddenly have its transformation matrix...
nuclear@0 154 // Don't know what to do there, I don't want to insert another node under the present root node
nuclear@0 155 // just to avoid this.
nuclear@0 156 CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes);
nuclear@0 157 }
nuclear@0 158
nuclear@0 159 // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
nuclear@0 160 MakeLeftHandedProcess convertProcess;
nuclear@0 161 convertProcess.Execute( pScene);
nuclear@0 162
nuclear@0 163 FlipWindingOrderProcess flipper;
nuclear@0 164 flipper.Execute(pScene);
nuclear@0 165
nuclear@0 166 // finally: create a dummy material if not material was imported
nuclear@0 167 if( pScene->mNumMaterials == 0)
nuclear@0 168 {
nuclear@0 169 pScene->mNumMaterials = 1;
nuclear@0 170 // create the Material
nuclear@0 171 aiMaterial* mat = new aiMaterial;
nuclear@0 172 int shadeMode = (int) aiShadingMode_Gouraud;
nuclear@0 173 mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
nuclear@0 174 // material colours
nuclear@0 175 int specExp = 1;
nuclear@0 176
nuclear@0 177 aiColor3D clr = aiColor3D( 0, 0, 0);
nuclear@0 178 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_EMISSIVE);
nuclear@0 179 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_SPECULAR);
nuclear@0 180
nuclear@0 181 clr = aiColor3D( 0.5f, 0.5f, 0.5f);
nuclear@0 182 mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 183 mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
nuclear@0 184
nuclear@0 185 pScene->mMaterials = new aiMaterial*[1];
nuclear@0 186 pScene->mMaterials[0] = mat;
nuclear@0 187 }
nuclear@0 188 }
nuclear@0 189
nuclear@0 190 // ------------------------------------------------------------------------------------------------
nuclear@0 191 // Recursively creates scene nodes from the imported hierarchy.
nuclear@0 192 aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode)
nuclear@0 193 {
nuclear@0 194 if( !pNode)
nuclear@0 195 return NULL;
nuclear@0 196
nuclear@0 197 // create node
nuclear@0 198 aiNode* node = new aiNode;
nuclear@0 199 node->mName.length = pNode->mName.length();
nuclear@0 200 node->mParent = pParent;
nuclear@0 201 memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length());
nuclear@0 202 node->mName.data[node->mName.length] = 0;
nuclear@0 203 node->mTransformation = pNode->mTrafoMatrix;
nuclear@0 204
nuclear@0 205 // convert meshes from the source node
nuclear@0 206 CreateMeshes( pScene, node, pNode->mMeshes);
nuclear@0 207
nuclear@0 208 // handle childs
nuclear@0 209 if( pNode->mChildren.size() > 0)
nuclear@0 210 {
nuclear@0 211 node->mNumChildren = (unsigned int)pNode->mChildren.size();
nuclear@0 212 node->mChildren = new aiNode* [node->mNumChildren];
nuclear@0 213
nuclear@0 214 for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
nuclear@0 215 node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]);
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 return node;
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 // ------------------------------------------------------------------------------------------------
nuclear@0 222 // Creates the meshes for the given node.
nuclear@0 223 void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes)
nuclear@0 224 {
nuclear@0 225 if( pMeshes.size() == 0)
nuclear@0 226 return;
nuclear@0 227
nuclear@0 228 // create a mesh for each mesh-material combination in the source node
nuclear@0 229 std::vector<aiMesh*> meshes;
nuclear@0 230 for( unsigned int a = 0; a < pMeshes.size(); a++)
nuclear@0 231 {
nuclear@0 232 XFile::Mesh* sourceMesh = pMeshes[a];
nuclear@0 233 // first convert its materials so that we can find them with their index afterwards
nuclear@0 234 ConvertMaterials( pScene, sourceMesh->mMaterials);
nuclear@0 235
nuclear@0 236 unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
nuclear@0 237 for( unsigned int b = 0; b < numMaterials; b++)
nuclear@0 238 {
nuclear@0 239 // collect the faces belonging to this material
nuclear@0 240 std::vector<unsigned int> faces;
nuclear@0 241 unsigned int numVertices = 0;
nuclear@0 242 if( sourceMesh->mFaceMaterials.size() > 0)
nuclear@0 243 {
nuclear@0 244 // if there is a per-face material defined, select the faces with the corresponding material
nuclear@0 245 for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++)
nuclear@0 246 {
nuclear@0 247 if( sourceMesh->mFaceMaterials[c] == b)
nuclear@0 248 {
nuclear@0 249 faces.push_back( c);
nuclear@0 250 numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
nuclear@0 251 }
nuclear@0 252 }
nuclear@0 253 } else
nuclear@0 254 {
nuclear@0 255 // if there is no per-face material, place everything into one mesh
nuclear@0 256 for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++)
nuclear@0 257 {
nuclear@0 258 faces.push_back( c);
nuclear@0 259 numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
nuclear@0 260 }
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 // no faces/vertices using this material? strange...
nuclear@0 264 if( numVertices == 0)
nuclear@0 265 continue;
nuclear@0 266
nuclear@0 267 // create a submesh using this material
nuclear@0 268 aiMesh* mesh = new aiMesh;
nuclear@0 269 meshes.push_back( mesh);
nuclear@0 270
nuclear@0 271 // find the material in the scene's material list. Either own material
nuclear@0 272 // or referenced material, it should already have a valid index
nuclear@0 273 if( sourceMesh->mFaceMaterials.size() > 0)
nuclear@0 274 {
nuclear@0 275 mesh->mMaterialIndex = sourceMesh->mMaterials[b].sceneIndex;
nuclear@0 276 } else
nuclear@0 277 {
nuclear@0 278 mesh->mMaterialIndex = 0;
nuclear@0 279 }
nuclear@0 280
nuclear@0 281 // Create properly sized data arrays in the mesh. We store unique vertices per face,
nuclear@0 282 // as specified
nuclear@0 283 mesh->mNumVertices = numVertices;
nuclear@0 284 mesh->mVertices = new aiVector3D[numVertices];
nuclear@0 285 mesh->mNumFaces = (unsigned int)faces.size();
nuclear@0 286 mesh->mFaces = new aiFace[mesh->mNumFaces];
nuclear@0 287
nuclear@0 288 // normals?
nuclear@0 289 if( sourceMesh->mNormals.size() > 0)
nuclear@0 290 mesh->mNormals = new aiVector3D[numVertices];
nuclear@0 291 // texture coords
nuclear@0 292 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++)
nuclear@0 293 {
nuclear@0 294 if( sourceMesh->mTexCoords[c].size() > 0)
nuclear@0 295 mesh->mTextureCoords[c] = new aiVector3D[numVertices];
nuclear@0 296 }
nuclear@0 297 // vertex colors
nuclear@0 298 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++)
nuclear@0 299 {
nuclear@0 300 if( sourceMesh->mColors[c].size() > 0)
nuclear@0 301 mesh->mColors[c] = new aiColor4D[numVertices];
nuclear@0 302 }
nuclear@0 303
nuclear@0 304 // now collect the vertex data of all data streams present in the imported mesh
nuclear@0 305 unsigned int newIndex = 0;
nuclear@0 306 std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
nuclear@0 307 orgPoints.resize( numVertices, 0);
nuclear@0 308
nuclear@0 309 for( unsigned int c = 0; c < faces.size(); c++)
nuclear@0 310 {
nuclear@0 311 unsigned int f = faces[c]; // index of the source face
nuclear@0 312 const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
nuclear@0 313
nuclear@0 314 // create face. either triangle or triangle fan depending on the index count
nuclear@0 315 aiFace& df = mesh->mFaces[c]; // destination face
nuclear@0 316 df.mNumIndices = (unsigned int)pf.mIndices.size();
nuclear@0 317 df.mIndices = new unsigned int[ df.mNumIndices];
nuclear@0 318
nuclear@0 319 // collect vertex data for indices of this face
nuclear@0 320 for( unsigned int d = 0; d < df.mNumIndices; d++)
nuclear@0 321 {
nuclear@0 322 df.mIndices[d] = newIndex;
nuclear@0 323 orgPoints[newIndex] = pf.mIndices[d];
nuclear@0 324
nuclear@0 325 // Position
nuclear@0 326 mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
nuclear@0 327 // Normal, if present
nuclear@0 328 if( mesh->HasNormals())
nuclear@0 329 mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]];
nuclear@0 330
nuclear@0 331 // texture coord sets
nuclear@0 332 for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++)
nuclear@0 333 {
nuclear@0 334 if( mesh->HasTextureCoords( e))
nuclear@0 335 {
nuclear@0 336 aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
nuclear@0 337 mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
nuclear@0 338 }
nuclear@0 339 }
nuclear@0 340 // vertex color sets
nuclear@0 341 for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++)
nuclear@0 342 if( mesh->HasVertexColors( e))
nuclear@0 343 mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
nuclear@0 344
nuclear@0 345 newIndex++;
nuclear@0 346 }
nuclear@0 347 }
nuclear@0 348
nuclear@0 349 // there should be as much new vertices as we calculated before
nuclear@0 350 ai_assert( newIndex == numVertices);
nuclear@0 351
nuclear@0 352 // convert all bones of the source mesh which influence vertices in this newly created mesh
nuclear@0 353 const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
nuclear@0 354 std::vector<aiBone*> newBones;
nuclear@0 355 for( unsigned int c = 0; c < bones.size(); c++)
nuclear@0 356 {
nuclear@0 357 const XFile::Bone& obone = bones[c];
nuclear@0 358 // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
nuclear@0 359 std::vector<float> oldWeights( sourceMesh->mPositions.size(), 0.0f);
nuclear@0 360 for( unsigned int d = 0; d < obone.mWeights.size(); d++)
nuclear@0 361 oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
nuclear@0 362
nuclear@0 363 // collect all vertex weights that influence a vertex in the new mesh
nuclear@0 364 std::vector<aiVertexWeight> newWeights;
nuclear@0 365 newWeights.reserve( numVertices);
nuclear@0 366 for( unsigned int d = 0; d < orgPoints.size(); d++)
nuclear@0 367 {
nuclear@0 368 // does the new vertex stem from an old vertex which was influenced by this bone?
nuclear@0 369 float w = oldWeights[orgPoints[d]];
nuclear@0 370 if( w > 0.0f)
nuclear@0 371 newWeights.push_back( aiVertexWeight( d, w));
nuclear@0 372 }
nuclear@0 373
nuclear@0 374 // if the bone has no weights in the newly created mesh, ignore it
nuclear@0 375 if( newWeights.size() == 0)
nuclear@0 376 continue;
nuclear@0 377
nuclear@0 378 // create
nuclear@0 379 aiBone* nbone = new aiBone;
nuclear@0 380 newBones.push_back( nbone);
nuclear@0 381 // copy name and matrix
nuclear@0 382 nbone->mName.Set( obone.mName);
nuclear@0 383 nbone->mOffsetMatrix = obone.mOffsetMatrix;
nuclear@0 384 nbone->mNumWeights = (unsigned int)newWeights.size();
nuclear@0 385 nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
nuclear@0 386 for( unsigned int d = 0; d < newWeights.size(); d++)
nuclear@0 387 nbone->mWeights[d] = newWeights[d];
nuclear@0 388 }
nuclear@0 389
nuclear@0 390 // store the bones in the mesh
nuclear@0 391 mesh->mNumBones = (unsigned int)newBones.size();
nuclear@0 392 if( newBones.size() > 0)
nuclear@0 393 {
nuclear@0 394 mesh->mBones = new aiBone*[mesh->mNumBones];
nuclear@0 395 std::copy( newBones.begin(), newBones.end(), mesh->mBones);
nuclear@0 396 }
nuclear@0 397 }
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 // reallocate scene mesh array to be large enough
nuclear@0 401 aiMesh** prevArray = pScene->mMeshes;
nuclear@0 402 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
nuclear@0 403 if( prevArray)
nuclear@0 404 {
nuclear@0 405 memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
nuclear@0 406 delete [] prevArray;
nuclear@0 407 }
nuclear@0 408
nuclear@0 409 // allocate mesh index array in the node
nuclear@0 410 pNode->mNumMeshes = (unsigned int)meshes.size();
nuclear@0 411 pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
nuclear@0 412
nuclear@0 413 // store all meshes in the mesh library of the scene and store their indices in the node
nuclear@0 414 for( unsigned int a = 0; a < meshes.size(); a++)
nuclear@0 415 {
nuclear@0 416 pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
nuclear@0 417 pNode->mMeshes[a] = pScene->mNumMeshes;
nuclear@0 418 pScene->mNumMeshes++;
nuclear@0 419 }
nuclear@0 420 }
nuclear@0 421
nuclear@0 422 // ------------------------------------------------------------------------------------------------
nuclear@0 423 // Converts the animations from the given imported data and creates them in the scene.
nuclear@0 424 void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData)
nuclear@0 425 {
nuclear@0 426 std::vector<aiAnimation*> newAnims;
nuclear@0 427
nuclear@0 428 for( unsigned int a = 0; a < pData->mAnims.size(); a++)
nuclear@0 429 {
nuclear@0 430 const XFile::Animation* anim = pData->mAnims[a];
nuclear@0 431 // some exporters mock me with empty animation tags.
nuclear@0 432 if( anim->mAnims.size() == 0)
nuclear@0 433 continue;
nuclear@0 434
nuclear@0 435 // create a new animation to hold the data
nuclear@0 436 aiAnimation* nanim = new aiAnimation;
nuclear@0 437 newAnims.push_back( nanim);
nuclear@0 438 nanim->mName.Set( anim->mName);
nuclear@0 439 // duration will be determined by the maximum length
nuclear@0 440 nanim->mDuration = 0;
nuclear@0 441 nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
nuclear@0 442 nanim->mNumChannels = (unsigned int)anim->mAnims.size();
nuclear@0 443 nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
nuclear@0 444
nuclear@0 445 for( unsigned int b = 0; b < anim->mAnims.size(); b++)
nuclear@0 446 {
nuclear@0 447 const XFile::AnimBone* bone = anim->mAnims[b];
nuclear@0 448 aiNodeAnim* nbone = new aiNodeAnim;
nuclear@0 449 nbone->mNodeName.Set( bone->mBoneName);
nuclear@0 450 nanim->mChannels[b] = nbone;
nuclear@0 451
nuclear@0 452 // keyframes are given as combined transformation matrix keys
nuclear@0 453 if( bone->mTrafoKeys.size() > 0)
nuclear@0 454 {
nuclear@0 455 nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
nuclear@0 456 nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
nuclear@0 457 nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size();
nuclear@0 458 nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
nuclear@0 459 nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
nuclear@0 460 nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
nuclear@0 461
nuclear@0 462 for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++)
nuclear@0 463 {
nuclear@0 464 // deconstruct each matrix into separate position, rotation and scaling
nuclear@0 465 double time = bone->mTrafoKeys[c].mTime;
nuclear@0 466 aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
nuclear@0 467
nuclear@0 468 // extract position
nuclear@0 469 aiVector3D pos( trafo.a4, trafo.b4, trafo.c4);
nuclear@0 470
nuclear@0 471 nbone->mPositionKeys[c].mTime = time;
nuclear@0 472 nbone->mPositionKeys[c].mValue = pos;
nuclear@0 473
nuclear@0 474 // extract scaling
nuclear@0 475 aiVector3D scale;
nuclear@0 476 scale.x = aiVector3D( trafo.a1, trafo.b1, trafo.c1).Length();
nuclear@0 477 scale.y = aiVector3D( trafo.a2, trafo.b2, trafo.c2).Length();
nuclear@0 478 scale.z = aiVector3D( trafo.a3, trafo.b3, trafo.c3).Length();
nuclear@0 479 nbone->mScalingKeys[c].mTime = time;
nuclear@0 480 nbone->mScalingKeys[c].mValue = scale;
nuclear@0 481
nuclear@0 482 // reconstruct rotation matrix without scaling
nuclear@0 483 aiMatrix3x3 rotmat(
nuclear@0 484 trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
nuclear@0 485 trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
nuclear@0 486 trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
nuclear@0 487
nuclear@0 488 // and convert it into a quaternion
nuclear@0 489 nbone->mRotationKeys[c].mTime = time;
nuclear@0 490 nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
nuclear@0 491 }
nuclear@0 492
nuclear@0 493 // longest lasting key sequence determines duration
nuclear@0 494 nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
nuclear@0 495 } else
nuclear@0 496 {
nuclear@0 497 // separate key sequences for position, rotation, scaling
nuclear@0 498 nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
nuclear@0 499 nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
nuclear@0 500 for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++)
nuclear@0 501 {
nuclear@0 502 aiVector3D pos = bone->mPosKeys[c].mValue;
nuclear@0 503
nuclear@0 504 nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
nuclear@0 505 nbone->mPositionKeys[c].mValue = pos;
nuclear@0 506 }
nuclear@0 507
nuclear@0 508 // rotation
nuclear@0 509 nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
nuclear@0 510 nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
nuclear@0 511 for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++)
nuclear@0 512 {
nuclear@0 513 aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
nuclear@0 514
nuclear@0 515 nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
nuclear@0 516 nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
nuclear@0 517 nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion
nuclear@0 518 }
nuclear@0 519
nuclear@0 520 // scaling
nuclear@0 521 nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size();
nuclear@0 522 nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
nuclear@0 523 for( unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
nuclear@0 524 nbone->mScalingKeys[c] = bone->mScaleKeys[c];
nuclear@0 525
nuclear@0 526 // longest lasting key sequence determines duration
nuclear@0 527 if( bone->mPosKeys.size() > 0)
nuclear@0 528 nanim->mDuration = std::max( nanim->mDuration, bone->mPosKeys.back().mTime);
nuclear@0 529 if( bone->mRotKeys.size() > 0)
nuclear@0 530 nanim->mDuration = std::max( nanim->mDuration, bone->mRotKeys.back().mTime);
nuclear@0 531 if( bone->mScaleKeys.size() > 0)
nuclear@0 532 nanim->mDuration = std::max( nanim->mDuration, bone->mScaleKeys.back().mTime);
nuclear@0 533 }
nuclear@0 534 }
nuclear@0 535 }
nuclear@0 536
nuclear@0 537 // store all converted animations in the scene
nuclear@0 538 if( newAnims.size() > 0)
nuclear@0 539 {
nuclear@0 540 pScene->mNumAnimations = (unsigned int)newAnims.size();
nuclear@0 541 pScene->mAnimations = new aiAnimation* [pScene->mNumAnimations];
nuclear@0 542 for( unsigned int a = 0; a < newAnims.size(); a++)
nuclear@0 543 pScene->mAnimations[a] = newAnims[a];
nuclear@0 544 }
nuclear@0 545 }
nuclear@0 546
nuclear@0 547 // ------------------------------------------------------------------------------------------------
nuclear@0 548 // Converts all materials in the given array and stores them in the scene's material list.
nuclear@0 549 void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
nuclear@0 550 {
nuclear@0 551 // count the non-referrer materials in the array
nuclear@0 552 unsigned int numNewMaterials = 0;
nuclear@0 553 for( unsigned int a = 0; a < pMaterials.size(); a++)
nuclear@0 554 if( !pMaterials[a].mIsReference)
nuclear@0 555 numNewMaterials++;
nuclear@0 556
nuclear@0 557 // resize the scene's material list to offer enough space for the new materials
nuclear@0 558 if( numNewMaterials > 0 )
nuclear@0 559 {
nuclear@0 560 aiMaterial** prevMats = pScene->mMaterials;
nuclear@0 561 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
nuclear@0 562 if( prevMats)
nuclear@0 563 {
nuclear@0 564 memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
nuclear@0 565 delete [] prevMats;
nuclear@0 566 }
nuclear@0 567 }
nuclear@0 568
nuclear@0 569 // convert all the materials given in the array
nuclear@0 570 for( unsigned int a = 0; a < pMaterials.size(); a++)
nuclear@0 571 {
nuclear@0 572 XFile::Material& oldMat = pMaterials[a];
nuclear@0 573 if( oldMat.mIsReference)
nuclear@0 574 {
nuclear@0 575 // find the material it refers to by name, and store its index
nuclear@0 576 for( size_t a = 0; a < pScene->mNumMaterials; ++a )
nuclear@0 577 {
nuclear@0 578 aiString name;
nuclear@0 579 pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
nuclear@0 580 if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 )
nuclear@0 581 {
nuclear@0 582 oldMat.sceneIndex = a;
nuclear@0 583 break;
nuclear@0 584 }
nuclear@0 585 }
nuclear@0 586
nuclear@0 587 if( oldMat.sceneIndex == SIZE_MAX )
nuclear@0 588 {
nuclear@0 589 DefaultLogger::get()->warn( boost::str( boost::format( "Could not resolve global material reference \"%s\"") % oldMat.mName));
nuclear@0 590 oldMat.sceneIndex = 0;
nuclear@0 591 }
nuclear@0 592
nuclear@0 593 continue;
nuclear@0 594 }
nuclear@0 595
nuclear@0 596 aiMaterial* mat = new aiMaterial;
nuclear@0 597 aiString name;
nuclear@0 598 name.Set( oldMat.mName);
nuclear@0 599 mat->AddProperty( &name, AI_MATKEY_NAME);
nuclear@0 600
nuclear@0 601 // Shading model: hardcoded to PHONG, there is no such information in an XFile
nuclear@0 602 // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
nuclear@0 603 // for some models in the SDK (e.g. good old tiny.x)
nuclear@0 604 int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
nuclear@0 605 ? aiShadingMode_Gouraud : aiShadingMode_Phong;
nuclear@0 606
nuclear@0 607 mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
nuclear@0 608 // material colours
nuclear@0 609 // Unclear: there's no ambient colour, but emissive. What to put for ambient?
nuclear@0 610 // Probably nothing at all, let the user select a suitable default.
nuclear@0 611 mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
nuclear@0 612 mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 613 mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
nuclear@0 614 mat->AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
nuclear@0 615
nuclear@0 616
nuclear@0 617 // texture, if there is one
nuclear@0 618 if (1 == oldMat.mTextures.size())
nuclear@0 619 {
nuclear@0 620 const XFile::TexEntry& otex = oldMat.mTextures.back();
nuclear@0 621 if (otex.mName.length())
nuclear@0 622 {
nuclear@0 623 // if there is only one texture assume it contains the diffuse color
nuclear@0 624 aiString tex( otex.mName);
nuclear@0 625 if( otex.mIsNormalMap)
nuclear@0 626 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(0));
nuclear@0 627 else
nuclear@0 628 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
nuclear@0 629 }
nuclear@0 630 }
nuclear@0 631 else
nuclear@0 632 {
nuclear@0 633 // Otherwise ... try to search for typical strings in the
nuclear@0 634 // texture's file name like 'bump' or 'diffuse'
nuclear@0 635 unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
nuclear@0 636 for( unsigned int b = 0; b < oldMat.mTextures.size(); b++)
nuclear@0 637 {
nuclear@0 638 const XFile::TexEntry& otex = oldMat.mTextures[b];
nuclear@0 639 std::string sz = otex.mName;
nuclear@0 640 if (!sz.length())continue;
nuclear@0 641
nuclear@0 642
nuclear@0 643 // find the file name
nuclear@0 644 //const size_t iLen = sz.length();
nuclear@0 645 std::string::size_type s = sz.find_last_of("\\/");
nuclear@0 646 if (std::string::npos == s)
nuclear@0 647 s = 0;
nuclear@0 648
nuclear@0 649 // cut off the file extension
nuclear@0 650 std::string::size_type sExt = sz.find_last_of('.');
nuclear@0 651 if (std::string::npos != sExt){
nuclear@0 652 sz[sExt] = '\0';
nuclear@0 653 }
nuclear@0 654
nuclear@0 655 // convert to lower case for easier comparision
nuclear@0 656 for( unsigned int c = 0; c < sz.length(); c++)
nuclear@0 657 if( isalpha( sz[c]))
nuclear@0 658 sz[c] = tolower( sz[c]);
nuclear@0 659
nuclear@0 660
nuclear@0 661 // Place texture filename property under the corresponding name
nuclear@0 662 aiString tex( oldMat.mTextures[b].mName);
nuclear@0 663
nuclear@0 664 // bump map
nuclear@0 665 if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s))
nuclear@0 666 {
nuclear@0 667 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
nuclear@0 668 } else
nuclear@0 669 if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
nuclear@0 670 {
nuclear@0 671 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
nuclear@0 672 } else
nuclear@0 673 if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
nuclear@0 674 {
nuclear@0 675 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
nuclear@0 676 } else
nuclear@0 677 if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
nuclear@0 678 {
nuclear@0 679 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
nuclear@0 680 } else
nuclear@0 681 if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
nuclear@0 682 {
nuclear@0 683 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
nuclear@0 684 } else
nuclear@0 685 {
nuclear@0 686 // Assume it is a diffuse texture
nuclear@0 687 mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
nuclear@0 688 }
nuclear@0 689 }
nuclear@0 690 }
nuclear@0 691
nuclear@0 692 pScene->mMaterials[pScene->mNumMaterials] = mat;
nuclear@0 693 oldMat.sceneIndex = pScene->mNumMaterials;
nuclear@0 694 pScene->mNumMaterials++;
nuclear@0 695 }
nuclear@0 696 }
nuclear@0 697
nuclear@0 698 #endif // !! ASSIMP_BUILD_NO_X_IMPORTER
nuclear@0 699