vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/XFileImporter.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,699 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 +copyright notice, this list of conditions and the 1.19 +following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 +copyright notice, this list of conditions and the 1.23 +following disclaimer in the documentation and/or other 1.24 +materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 +contributors may be used to endorse or promote products 1.28 +derived from this software without specific prior 1.29 +written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 +/** @file XFileImporter.cpp 1.45 + * @brief Implementation of the XFile importer class 1.46 + */ 1.47 + 1.48 +#include "AssimpPCH.h" 1.49 +#ifndef ASSIMP_BUILD_NO_X_IMPORTER 1.50 + 1.51 +#include "XFileImporter.h" 1.52 +#include "XFileParser.h" 1.53 +#include "ConvertToLHProcess.h" 1.54 + 1.55 +using namespace Assimp; 1.56 + 1.57 +static const aiImporterDesc desc = { 1.58 + "Direct3D XFile Importer", 1.59 + "", 1.60 + "", 1.61 + "", 1.62 + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour, 1.63 + 1, 1.64 + 3, 1.65 + 1, 1.66 + 5, 1.67 + "x" 1.68 +}; 1.69 + 1.70 +// ------------------------------------------------------------------------------------------------ 1.71 +// Constructor to be privately used by Importer 1.72 +XFileImporter::XFileImporter() 1.73 +{} 1.74 + 1.75 +// ------------------------------------------------------------------------------------------------ 1.76 +// Destructor, private as well 1.77 +XFileImporter::~XFileImporter() 1.78 +{} 1.79 + 1.80 +// ------------------------------------------------------------------------------------------------ 1.81 +// Returns whether the class can handle the format of the given file. 1.82 +bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.83 +{ 1.84 + std::string extension = GetExtension(pFile); 1.85 + if(extension == "x") { 1.86 + return true; 1.87 + } 1.88 + if (!extension.length() || checkSig) { 1.89 + uint32_t token[1]; 1.90 + token[0] = AI_MAKE_MAGIC("xof "); 1.91 + return CheckMagicToken(pIOHandler,pFile,token,1,0); 1.92 + } 1.93 + return false; 1.94 +} 1.95 + 1.96 +// ------------------------------------------------------------------------------------------------ 1.97 +// Get file extension list 1.98 +const aiImporterDesc* XFileImporter::GetInfo () const 1.99 +{ 1.100 + return &desc; 1.101 +} 1.102 + 1.103 +// ------------------------------------------------------------------------------------------------ 1.104 +// Imports the given file into the given scene structure. 1.105 +void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) 1.106 +{ 1.107 + // read file into memory 1.108 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); 1.109 + if( file.get() == NULL) 1.110 + throw DeadlyImportError( "Failed to open file " + pFile + "."); 1.111 + 1.112 + size_t fileSize = file->FileSize(); 1.113 + if( fileSize < 16) 1.114 + throw DeadlyImportError( "XFile is too small."); 1.115 + 1.116 + // in the hope that binary files will never start with a BOM ... 1.117 + mBuffer.resize( fileSize + 1); 1.118 + file->Read( &mBuffer.front(), 1, fileSize); 1.119 + ConvertToUTF8(mBuffer); 1.120 + 1.121 + // parse the file into a temporary representation 1.122 + XFileParser parser( mBuffer); 1.123 + 1.124 + // and create the proper return structures out of it 1.125 + CreateDataRepresentationFromImport( pScene, parser.GetImportedData()); 1.126 + 1.127 + // if nothing came from it, report it as error 1.128 + if( !pScene->mRootNode) 1.129 + throw DeadlyImportError( "XFile is ill-formatted - no content imported."); 1.130 +} 1.131 + 1.132 +// ------------------------------------------------------------------------------------------------ 1.133 +// Constructs the return data structure out of the imported data. 1.134 +void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::Scene* pData) 1.135 +{ 1.136 + // Read the global materials first so that meshes referring to them can find them later 1.137 + ConvertMaterials( pScene, pData->mGlobalMaterials); 1.138 + 1.139 + // copy nodes, extracting meshes and materials on the way 1.140 + pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode); 1.141 + 1.142 + // extract animations 1.143 + CreateAnimations( pScene, pData); 1.144 + 1.145 + // read the global meshes that were stored outside of any node 1.146 + if( pData->mGlobalMeshes.size() > 0) 1.147 + { 1.148 + // create a root node to hold them if there isn't any, yet 1.149 + if( pScene->mRootNode == NULL) 1.150 + { 1.151 + pScene->mRootNode = new aiNode; 1.152 + pScene->mRootNode->mName.Set( "$dummy_node"); 1.153 + } 1.154 + 1.155 + // convert all global meshes and store them in the root node. 1.156 + // If there was one before, the global meshes now suddenly have its transformation matrix... 1.157 + // Don't know what to do there, I don't want to insert another node under the present root node 1.158 + // just to avoid this. 1.159 + CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes); 1.160 + } 1.161 + 1.162 + // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly 1.163 + MakeLeftHandedProcess convertProcess; 1.164 + convertProcess.Execute( pScene); 1.165 + 1.166 + FlipWindingOrderProcess flipper; 1.167 + flipper.Execute(pScene); 1.168 + 1.169 + // finally: create a dummy material if not material was imported 1.170 + if( pScene->mNumMaterials == 0) 1.171 + { 1.172 + pScene->mNumMaterials = 1; 1.173 + // create the Material 1.174 + aiMaterial* mat = new aiMaterial; 1.175 + int shadeMode = (int) aiShadingMode_Gouraud; 1.176 + mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL); 1.177 + // material colours 1.178 + int specExp = 1; 1.179 + 1.180 + aiColor3D clr = aiColor3D( 0, 0, 0); 1.181 + mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_EMISSIVE); 1.182 + mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_SPECULAR); 1.183 + 1.184 + clr = aiColor3D( 0.5f, 0.5f, 0.5f); 1.185 + mat->AddProperty( &clr, 1, AI_MATKEY_COLOR_DIFFUSE); 1.186 + mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS); 1.187 + 1.188 + pScene->mMaterials = new aiMaterial*[1]; 1.189 + pScene->mMaterials[0] = mat; 1.190 + } 1.191 +} 1.192 + 1.193 +// ------------------------------------------------------------------------------------------------ 1.194 +// Recursively creates scene nodes from the imported hierarchy. 1.195 +aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) 1.196 +{ 1.197 + if( !pNode) 1.198 + return NULL; 1.199 + 1.200 + // create node 1.201 + aiNode* node = new aiNode; 1.202 + node->mName.length = pNode->mName.length(); 1.203 + node->mParent = pParent; 1.204 + memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length()); 1.205 + node->mName.data[node->mName.length] = 0; 1.206 + node->mTransformation = pNode->mTrafoMatrix; 1.207 + 1.208 + // convert meshes from the source node 1.209 + CreateMeshes( pScene, node, pNode->mMeshes); 1.210 + 1.211 + // handle childs 1.212 + if( pNode->mChildren.size() > 0) 1.213 + { 1.214 + node->mNumChildren = (unsigned int)pNode->mChildren.size(); 1.215 + node->mChildren = new aiNode* [node->mNumChildren]; 1.216 + 1.217 + for( unsigned int a = 0; a < pNode->mChildren.size(); a++) 1.218 + node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]); 1.219 + } 1.220 + 1.221 + return node; 1.222 +} 1.223 + 1.224 +// ------------------------------------------------------------------------------------------------ 1.225 +// Creates the meshes for the given node. 1.226 +void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) 1.227 +{ 1.228 + if( pMeshes.size() == 0) 1.229 + return; 1.230 + 1.231 + // create a mesh for each mesh-material combination in the source node 1.232 + std::vector<aiMesh*> meshes; 1.233 + for( unsigned int a = 0; a < pMeshes.size(); a++) 1.234 + { 1.235 + XFile::Mesh* sourceMesh = pMeshes[a]; 1.236 + // first convert its materials so that we can find them with their index afterwards 1.237 + ConvertMaterials( pScene, sourceMesh->mMaterials); 1.238 + 1.239 + unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u); 1.240 + for( unsigned int b = 0; b < numMaterials; b++) 1.241 + { 1.242 + // collect the faces belonging to this material 1.243 + std::vector<unsigned int> faces; 1.244 + unsigned int numVertices = 0; 1.245 + if( sourceMesh->mFaceMaterials.size() > 0) 1.246 + { 1.247 + // if there is a per-face material defined, select the faces with the corresponding material 1.248 + for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++) 1.249 + { 1.250 + if( sourceMesh->mFaceMaterials[c] == b) 1.251 + { 1.252 + faces.push_back( c); 1.253 + numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); 1.254 + } 1.255 + } 1.256 + } else 1.257 + { 1.258 + // if there is no per-face material, place everything into one mesh 1.259 + for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++) 1.260 + { 1.261 + faces.push_back( c); 1.262 + numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); 1.263 + } 1.264 + } 1.265 + 1.266 + // no faces/vertices using this material? strange... 1.267 + if( numVertices == 0) 1.268 + continue; 1.269 + 1.270 + // create a submesh using this material 1.271 + aiMesh* mesh = new aiMesh; 1.272 + meshes.push_back( mesh); 1.273 + 1.274 + // find the material in the scene's material list. Either own material 1.275 + // or referenced material, it should already have a valid index 1.276 + if( sourceMesh->mFaceMaterials.size() > 0) 1.277 + { 1.278 + mesh->mMaterialIndex = sourceMesh->mMaterials[b].sceneIndex; 1.279 + } else 1.280 + { 1.281 + mesh->mMaterialIndex = 0; 1.282 + } 1.283 + 1.284 + // Create properly sized data arrays in the mesh. We store unique vertices per face, 1.285 + // as specified 1.286 + mesh->mNumVertices = numVertices; 1.287 + mesh->mVertices = new aiVector3D[numVertices]; 1.288 + mesh->mNumFaces = (unsigned int)faces.size(); 1.289 + mesh->mFaces = new aiFace[mesh->mNumFaces]; 1.290 + 1.291 + // normals? 1.292 + if( sourceMesh->mNormals.size() > 0) 1.293 + mesh->mNormals = new aiVector3D[numVertices]; 1.294 + // texture coords 1.295 + for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++) 1.296 + { 1.297 + if( sourceMesh->mTexCoords[c].size() > 0) 1.298 + mesh->mTextureCoords[c] = new aiVector3D[numVertices]; 1.299 + } 1.300 + // vertex colors 1.301 + for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++) 1.302 + { 1.303 + if( sourceMesh->mColors[c].size() > 0) 1.304 + mesh->mColors[c] = new aiColor4D[numVertices]; 1.305 + } 1.306 + 1.307 + // now collect the vertex data of all data streams present in the imported mesh 1.308 + unsigned int newIndex = 0; 1.309 + std::vector<unsigned int> orgPoints; // from which original point each new vertex stems 1.310 + orgPoints.resize( numVertices, 0); 1.311 + 1.312 + for( unsigned int c = 0; c < faces.size(); c++) 1.313 + { 1.314 + unsigned int f = faces[c]; // index of the source face 1.315 + const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face 1.316 + 1.317 + // create face. either triangle or triangle fan depending on the index count 1.318 + aiFace& df = mesh->mFaces[c]; // destination face 1.319 + df.mNumIndices = (unsigned int)pf.mIndices.size(); 1.320 + df.mIndices = new unsigned int[ df.mNumIndices]; 1.321 + 1.322 + // collect vertex data for indices of this face 1.323 + for( unsigned int d = 0; d < df.mNumIndices; d++) 1.324 + { 1.325 + df.mIndices[d] = newIndex; 1.326 + orgPoints[newIndex] = pf.mIndices[d]; 1.327 + 1.328 + // Position 1.329 + mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]]; 1.330 + // Normal, if present 1.331 + if( mesh->HasNormals()) 1.332 + mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]]; 1.333 + 1.334 + // texture coord sets 1.335 + for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) 1.336 + { 1.337 + if( mesh->HasTextureCoords( e)) 1.338 + { 1.339 + aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]]; 1.340 + mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f); 1.341 + } 1.342 + } 1.343 + // vertex color sets 1.344 + for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++) 1.345 + if( mesh->HasVertexColors( e)) 1.346 + mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]]; 1.347 + 1.348 + newIndex++; 1.349 + } 1.350 + } 1.351 + 1.352 + // there should be as much new vertices as we calculated before 1.353 + ai_assert( newIndex == numVertices); 1.354 + 1.355 + // convert all bones of the source mesh which influence vertices in this newly created mesh 1.356 + const std::vector<XFile::Bone>& bones = sourceMesh->mBones; 1.357 + std::vector<aiBone*> newBones; 1.358 + for( unsigned int c = 0; c < bones.size(); c++) 1.359 + { 1.360 + const XFile::Bone& obone = bones[c]; 1.361 + // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex 1.362 + std::vector<float> oldWeights( sourceMesh->mPositions.size(), 0.0f); 1.363 + for( unsigned int d = 0; d < obone.mWeights.size(); d++) 1.364 + oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight; 1.365 + 1.366 + // collect all vertex weights that influence a vertex in the new mesh 1.367 + std::vector<aiVertexWeight> newWeights; 1.368 + newWeights.reserve( numVertices); 1.369 + for( unsigned int d = 0; d < orgPoints.size(); d++) 1.370 + { 1.371 + // does the new vertex stem from an old vertex which was influenced by this bone? 1.372 + float w = oldWeights[orgPoints[d]]; 1.373 + if( w > 0.0f) 1.374 + newWeights.push_back( aiVertexWeight( d, w)); 1.375 + } 1.376 + 1.377 + // if the bone has no weights in the newly created mesh, ignore it 1.378 + if( newWeights.size() == 0) 1.379 + continue; 1.380 + 1.381 + // create 1.382 + aiBone* nbone = new aiBone; 1.383 + newBones.push_back( nbone); 1.384 + // copy name and matrix 1.385 + nbone->mName.Set( obone.mName); 1.386 + nbone->mOffsetMatrix = obone.mOffsetMatrix; 1.387 + nbone->mNumWeights = (unsigned int)newWeights.size(); 1.388 + nbone->mWeights = new aiVertexWeight[nbone->mNumWeights]; 1.389 + for( unsigned int d = 0; d < newWeights.size(); d++) 1.390 + nbone->mWeights[d] = newWeights[d]; 1.391 + } 1.392 + 1.393 + // store the bones in the mesh 1.394 + mesh->mNumBones = (unsigned int)newBones.size(); 1.395 + if( newBones.size() > 0) 1.396 + { 1.397 + mesh->mBones = new aiBone*[mesh->mNumBones]; 1.398 + std::copy( newBones.begin(), newBones.end(), mesh->mBones); 1.399 + } 1.400 + } 1.401 + } 1.402 + 1.403 + // reallocate scene mesh array to be large enough 1.404 + aiMesh** prevArray = pScene->mMeshes; 1.405 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()]; 1.406 + if( prevArray) 1.407 + { 1.408 + memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*)); 1.409 + delete [] prevArray; 1.410 + } 1.411 + 1.412 + // allocate mesh index array in the node 1.413 + pNode->mNumMeshes = (unsigned int)meshes.size(); 1.414 + pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; 1.415 + 1.416 + // store all meshes in the mesh library of the scene and store their indices in the node 1.417 + for( unsigned int a = 0; a < meshes.size(); a++) 1.418 + { 1.419 + pScene->mMeshes[pScene->mNumMeshes] = meshes[a]; 1.420 + pNode->mMeshes[a] = pScene->mNumMeshes; 1.421 + pScene->mNumMeshes++; 1.422 + } 1.423 +} 1.424 + 1.425 +// ------------------------------------------------------------------------------------------------ 1.426 +// Converts the animations from the given imported data and creates them in the scene. 1.427 +void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) 1.428 +{ 1.429 + std::vector<aiAnimation*> newAnims; 1.430 + 1.431 + for( unsigned int a = 0; a < pData->mAnims.size(); a++) 1.432 + { 1.433 + const XFile::Animation* anim = pData->mAnims[a]; 1.434 + // some exporters mock me with empty animation tags. 1.435 + if( anim->mAnims.size() == 0) 1.436 + continue; 1.437 + 1.438 + // create a new animation to hold the data 1.439 + aiAnimation* nanim = new aiAnimation; 1.440 + newAnims.push_back( nanim); 1.441 + nanim->mName.Set( anim->mName); 1.442 + // duration will be determined by the maximum length 1.443 + nanim->mDuration = 0; 1.444 + nanim->mTicksPerSecond = pData->mAnimTicksPerSecond; 1.445 + nanim->mNumChannels = (unsigned int)anim->mAnims.size(); 1.446 + nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels]; 1.447 + 1.448 + for( unsigned int b = 0; b < anim->mAnims.size(); b++) 1.449 + { 1.450 + const XFile::AnimBone* bone = anim->mAnims[b]; 1.451 + aiNodeAnim* nbone = new aiNodeAnim; 1.452 + nbone->mNodeName.Set( bone->mBoneName); 1.453 + nanim->mChannels[b] = nbone; 1.454 + 1.455 + // keyframes are given as combined transformation matrix keys 1.456 + if( bone->mTrafoKeys.size() > 0) 1.457 + { 1.458 + nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size(); 1.459 + nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; 1.460 + nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size(); 1.461 + nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys]; 1.462 + nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size(); 1.463 + nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys]; 1.464 + 1.465 + for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++) 1.466 + { 1.467 + // deconstruct each matrix into separate position, rotation and scaling 1.468 + double time = bone->mTrafoKeys[c].mTime; 1.469 + aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix; 1.470 + 1.471 + // extract position 1.472 + aiVector3D pos( trafo.a4, trafo.b4, trafo.c4); 1.473 + 1.474 + nbone->mPositionKeys[c].mTime = time; 1.475 + nbone->mPositionKeys[c].mValue = pos; 1.476 + 1.477 + // extract scaling 1.478 + aiVector3D scale; 1.479 + scale.x = aiVector3D( trafo.a1, trafo.b1, trafo.c1).Length(); 1.480 + scale.y = aiVector3D( trafo.a2, trafo.b2, trafo.c2).Length(); 1.481 + scale.z = aiVector3D( trafo.a3, trafo.b3, trafo.c3).Length(); 1.482 + nbone->mScalingKeys[c].mTime = time; 1.483 + nbone->mScalingKeys[c].mValue = scale; 1.484 + 1.485 + // reconstruct rotation matrix without scaling 1.486 + aiMatrix3x3 rotmat( 1.487 + trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z, 1.488 + trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z, 1.489 + trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z); 1.490 + 1.491 + // and convert it into a quaternion 1.492 + nbone->mRotationKeys[c].mTime = time; 1.493 + nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); 1.494 + } 1.495 + 1.496 + // longest lasting key sequence determines duration 1.497 + nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime); 1.498 + } else 1.499 + { 1.500 + // separate key sequences for position, rotation, scaling 1.501 + nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size(); 1.502 + nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; 1.503 + for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++) 1.504 + { 1.505 + aiVector3D pos = bone->mPosKeys[c].mValue; 1.506 + 1.507 + nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime; 1.508 + nbone->mPositionKeys[c].mValue = pos; 1.509 + } 1.510 + 1.511 + // rotation 1.512 + nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size(); 1.513 + nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys]; 1.514 + for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++) 1.515 + { 1.516 + aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix(); 1.517 + 1.518 + nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime; 1.519 + nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat); 1.520 + nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion 1.521 + } 1.522 + 1.523 + // scaling 1.524 + nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size(); 1.525 + nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys]; 1.526 + for( unsigned int c = 0; c < nbone->mNumScalingKeys; c++) 1.527 + nbone->mScalingKeys[c] = bone->mScaleKeys[c]; 1.528 + 1.529 + // longest lasting key sequence determines duration 1.530 + if( bone->mPosKeys.size() > 0) 1.531 + nanim->mDuration = std::max( nanim->mDuration, bone->mPosKeys.back().mTime); 1.532 + if( bone->mRotKeys.size() > 0) 1.533 + nanim->mDuration = std::max( nanim->mDuration, bone->mRotKeys.back().mTime); 1.534 + if( bone->mScaleKeys.size() > 0) 1.535 + nanim->mDuration = std::max( nanim->mDuration, bone->mScaleKeys.back().mTime); 1.536 + } 1.537 + } 1.538 + } 1.539 + 1.540 + // store all converted animations in the scene 1.541 + if( newAnims.size() > 0) 1.542 + { 1.543 + pScene->mNumAnimations = (unsigned int)newAnims.size(); 1.544 + pScene->mAnimations = new aiAnimation* [pScene->mNumAnimations]; 1.545 + for( unsigned int a = 0; a < newAnims.size(); a++) 1.546 + pScene->mAnimations[a] = newAnims[a]; 1.547 + } 1.548 +} 1.549 + 1.550 +// ------------------------------------------------------------------------------------------------ 1.551 +// Converts all materials in the given array and stores them in the scene's material list. 1.552 +void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials) 1.553 +{ 1.554 + // count the non-referrer materials in the array 1.555 + unsigned int numNewMaterials = 0; 1.556 + for( unsigned int a = 0; a < pMaterials.size(); a++) 1.557 + if( !pMaterials[a].mIsReference) 1.558 + numNewMaterials++; 1.559 + 1.560 + // resize the scene's material list to offer enough space for the new materials 1.561 + if( numNewMaterials > 0 ) 1.562 + { 1.563 + aiMaterial** prevMats = pScene->mMaterials; 1.564 + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials]; 1.565 + if( prevMats) 1.566 + { 1.567 + memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*)); 1.568 + delete [] prevMats; 1.569 + } 1.570 + } 1.571 + 1.572 + // convert all the materials given in the array 1.573 + for( unsigned int a = 0; a < pMaterials.size(); a++) 1.574 + { 1.575 + XFile::Material& oldMat = pMaterials[a]; 1.576 + if( oldMat.mIsReference) 1.577 + { 1.578 + // find the material it refers to by name, and store its index 1.579 + for( size_t a = 0; a < pScene->mNumMaterials; ++a ) 1.580 + { 1.581 + aiString name; 1.582 + pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name); 1.583 + if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) 1.584 + { 1.585 + oldMat.sceneIndex = a; 1.586 + break; 1.587 + } 1.588 + } 1.589 + 1.590 + if( oldMat.sceneIndex == SIZE_MAX ) 1.591 + { 1.592 + DefaultLogger::get()->warn( boost::str( boost::format( "Could not resolve global material reference \"%s\"") % oldMat.mName)); 1.593 + oldMat.sceneIndex = 0; 1.594 + } 1.595 + 1.596 + continue; 1.597 + } 1.598 + 1.599 + aiMaterial* mat = new aiMaterial; 1.600 + aiString name; 1.601 + name.Set( oldMat.mName); 1.602 + mat->AddProperty( &name, AI_MATKEY_NAME); 1.603 + 1.604 + // Shading model: hardcoded to PHONG, there is no such information in an XFile 1.605 + // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix 1.606 + // for some models in the SDK (e.g. good old tiny.x) 1.607 + int shadeMode = (int)oldMat.mSpecularExponent == 0.0f 1.608 + ? aiShadingMode_Gouraud : aiShadingMode_Phong; 1.609 + 1.610 + mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL); 1.611 + // material colours 1.612 + // Unclear: there's no ambient colour, but emissive. What to put for ambient? 1.613 + // Probably nothing at all, let the user select a suitable default. 1.614 + mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); 1.615 + mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); 1.616 + mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); 1.617 + mat->AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); 1.618 + 1.619 + 1.620 + // texture, if there is one 1.621 + if (1 == oldMat.mTextures.size()) 1.622 + { 1.623 + const XFile::TexEntry& otex = oldMat.mTextures.back(); 1.624 + if (otex.mName.length()) 1.625 + { 1.626 + // if there is only one texture assume it contains the diffuse color 1.627 + aiString tex( otex.mName); 1.628 + if( otex.mIsNormalMap) 1.629 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(0)); 1.630 + else 1.631 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.632 + } 1.633 + } 1.634 + else 1.635 + { 1.636 + // Otherwise ... try to search for typical strings in the 1.637 + // texture's file name like 'bump' or 'diffuse' 1.638 + unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0; 1.639 + for( unsigned int b = 0; b < oldMat.mTextures.size(); b++) 1.640 + { 1.641 + const XFile::TexEntry& otex = oldMat.mTextures[b]; 1.642 + std::string sz = otex.mName; 1.643 + if (!sz.length())continue; 1.644 + 1.645 + 1.646 + // find the file name 1.647 + //const size_t iLen = sz.length(); 1.648 + std::string::size_type s = sz.find_last_of("\\/"); 1.649 + if (std::string::npos == s) 1.650 + s = 0; 1.651 + 1.652 + // cut off the file extension 1.653 + std::string::size_type sExt = sz.find_last_of('.'); 1.654 + if (std::string::npos != sExt){ 1.655 + sz[sExt] = '\0'; 1.656 + } 1.657 + 1.658 + // convert to lower case for easier comparision 1.659 + for( unsigned int c = 0; c < sz.length(); c++) 1.660 + if( isalpha( sz[c])) 1.661 + sz[c] = tolower( sz[c]); 1.662 + 1.663 + 1.664 + // Place texture filename property under the corresponding name 1.665 + aiString tex( oldMat.mTextures[b].mName); 1.666 + 1.667 + // bump map 1.668 + if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) 1.669 + { 1.670 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++)); 1.671 + } else 1.672 + if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) 1.673 + { 1.674 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++)); 1.675 + } else 1.676 + if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) 1.677 + { 1.678 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++)); 1.679 + } else 1.680 + if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) 1.681 + { 1.682 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++)); 1.683 + } else 1.684 + if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) 1.685 + { 1.686 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++)); 1.687 + } else 1.688 + { 1.689 + // Assume it is a diffuse texture 1.690 + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++)); 1.691 + } 1.692 + } 1.693 + } 1.694 + 1.695 + pScene->mMaterials[pScene->mNumMaterials] = mat; 1.696 + oldMat.sceneIndex = pScene->mNumMaterials; 1.697 + pScene->mNumMaterials++; 1.698 + } 1.699 +} 1.700 + 1.701 +#endif // !! ASSIMP_BUILD_NO_X_IMPORTER 1.702 +