2
0

XFileImporter.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /** @file Implementation of the XFile importer class */
  2. #include "XFileImporter.h"
  3. #include "XFileParser.h"
  4. #include "MaterialSystem.h"
  5. #include "ConvertToLHProcess.h"
  6. #include "../include/IOStream.h"
  7. #include "../include/IOSystem.h"
  8. #include "../include/aiMesh.h"
  9. #include "../include/aiScene.h"
  10. #include <boost/scoped_ptr.hpp>
  11. #include <boost/format.hpp>
  12. using namespace Assimp;
  13. // ------------------------------------------------------------------------------------------------
  14. // Constructor to be privately used by Importer
  15. XFileImporter::XFileImporter()
  16. {
  17. }
  18. // ------------------------------------------------------------------------------------------------
  19. // Destructor, private as well
  20. XFileImporter::~XFileImporter()
  21. {
  22. }
  23. // ------------------------------------------------------------------------------------------------
  24. // Returns whether the class can handle the format of the given file.
  25. bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
  26. {
  27. // simple check of file extension is enough for the moment
  28. std::string::size_type pos = pFile.find_last_of( '.');
  29. // no file extension - can't read
  30. if( pos == std::string::npos)
  31. return false;
  32. std::string extension = pFile.substr( pos);
  33. if( extension == ".x" || extension == ".X")
  34. return true;
  35. return false;
  36. }
  37. // ------------------------------------------------------------------------------------------------
  38. // Imports the given file into the given scene structure.
  39. void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
  40. {
  41. // read file into memory
  42. boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
  43. if( file.get() == NULL)
  44. throw new ImportErrorException( "Failed to open file " + pFile + ".");
  45. size_t fileSize = file->FileSize();
  46. if( fileSize < 16)
  47. throw new ImportErrorException( "XFile is too small.");
  48. mBuffer.resize( fileSize);
  49. file->Read( &mBuffer.front(), 1, fileSize);
  50. // parse the file into a temporary representation
  51. XFileParser parser( mBuffer);
  52. // and create the proper return structures out of it
  53. CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
  54. }
  55. // ------------------------------------------------------------------------------------------------
  56. // Constructs the return data structure out of the imported data.
  57. void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, const XFile::Scene* pData)
  58. {
  59. // Read the global materials first so that meshes referring to them can find them later
  60. ConvertMaterials( pScene, pData->mGlobalMaterials);
  61. // copy nodes, extracting meshes and materials on the way
  62. pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode);
  63. // extract animations
  64. CreateAnimations( pScene, pData);
  65. // read the global meshes that were stored outside of any node
  66. if( pData->mGlobalMeshes.size() > 0)
  67. {
  68. // create a root node to hold them if there isn't any, yet
  69. if( pScene->mRootNode == NULL)
  70. {
  71. pScene->mRootNode = new aiNode;
  72. pScene->mRootNode->mName.Set( "$dummy_node");
  73. }
  74. // convert all global meshes and store them in the root node.
  75. // If there was one before, the global meshes now suddenly have its transformation matrix...
  76. // Don't know what to do there, I don't want to insert another node under the present root node
  77. // just to avoid this.
  78. CreateMeshes( pScene, pScene->mRootNode, pData->mGlobalMeshes);
  79. }
  80. // convert the root node's transformation to OGL coords
  81. ConvertToLHProcess::ConvertToOGL( pScene->mRootNode->mTransformation);
  82. // finally: create a dummy material if not material was imported
  83. if( pScene->mNumMaterials == 0)
  84. {
  85. pScene->mNumMaterials = 1;
  86. // create the Material
  87. Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
  88. int shadeMode = (int) aiShadingMode_Gouraud;
  89. mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
  90. // material colours
  91. int specExp = 1;
  92. mat->AddProperty( &aiColor3D( 0, 0, 0), 1, AI_MATKEY_COLOR_EMISSIVE);
  93. mat->AddProperty( &aiColor3D( 0.5f, 0.5f, 0.5f), 1, AI_MATKEY_COLOR_DIFFUSE);
  94. mat->AddProperty( &aiColor3D( 0, 0, 0), 1, AI_MATKEY_COLOR_SPECULAR);
  95. mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
  96. pScene->mMaterials = new aiMaterial*[1];
  97. pScene->mMaterials[0] = mat;
  98. }
  99. }
  100. // ------------------------------------------------------------------------------------------------
  101. // Recursively creates scene nodes from the imported hierarchy.
  102. aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode)
  103. {
  104. if( !pNode)
  105. return NULL;
  106. // create node
  107. aiNode* node = new aiNode;
  108. node->mName.length = pNode->mName.length();
  109. node->mParent = pParent;
  110. memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length());
  111. node->mName.data[node->mName.length] = 0;
  112. node->mTransformation = pNode->mTrafoMatrix;
  113. // convert meshes from the source node
  114. CreateMeshes( pScene, node, pNode->mMeshes);
  115. // handle childs
  116. if( pNode->mChildren.size() > 0)
  117. {
  118. node->mNumChildren = pNode->mChildren.size();
  119. node->mChildren = new aiNode* [node->mNumChildren];
  120. for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
  121. node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]);
  122. }
  123. return node;
  124. }
  125. // ------------------------------------------------------------------------------------------------
  126. // Creates the meshes for the given node.
  127. void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes)
  128. {
  129. if( pMeshes.size() == 0)
  130. return;
  131. // create a mesh for each mesh-material combination in the source node
  132. std::vector<aiMesh*> meshes;
  133. for( unsigned int a = 0; a < pMeshes.size(); a++)
  134. {
  135. const XFile::Mesh* sourceMesh = pMeshes[a];
  136. // first convert its materials so that we can find them when searching by name afterwards
  137. ConvertMaterials( pScene, sourceMesh->mMaterials);
  138. unsigned int numMaterials = std::max( sourceMesh->mMaterials.size(), 1u);
  139. for( unsigned int b = 0; b < numMaterials; b++)
  140. {
  141. // collect the faces belonging to this material
  142. std::vector<unsigned int> faces;
  143. unsigned int numVertices = 0;
  144. if( sourceMesh->mFaceMaterials.size() > 0)
  145. {
  146. // if there is a per-face material defined, select the faces with the corresponding material
  147. for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++)
  148. {
  149. if( sourceMesh->mFaceMaterials[c] == b)
  150. {
  151. faces.push_back( c);
  152. numVertices += sourceMesh->mPosFaces[c].mIndices.size();
  153. }
  154. }
  155. } else
  156. {
  157. // if there is no per-face material, place everything into one mesh
  158. for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++)
  159. {
  160. faces.push_back( c);
  161. numVertices += sourceMesh->mPosFaces[c].mIndices.size();
  162. }
  163. }
  164. // no faces/vertices using this material? strange...
  165. if( numVertices == 0)
  166. continue;
  167. // create a submesh using this material
  168. aiMesh* mesh = new aiMesh;
  169. meshes.push_back( mesh);
  170. // find the material by name in the scene's material list. Either own material
  171. // or referenced material, it should already be found there
  172. if( sourceMesh->mFaceMaterials.size() > 0)
  173. {
  174. std::map<std::string, unsigned int>::const_iterator matIt = mImportedMats.find( sourceMesh->mMaterials[b].mName);
  175. if( matIt == mImportedMats.end())
  176. mesh->mMaterialIndex = 0;
  177. else
  178. mesh->mMaterialIndex = matIt->second;
  179. } else
  180. {
  181. mesh->mMaterialIndex = 0;
  182. }
  183. // Create properly sized data arrays in the mesh. We store unique vertices per face,
  184. // as specified
  185. mesh->mNumVertices = numVertices;
  186. mesh->mVertices = new aiVector3D[numVertices];
  187. mesh->mNumFaces = faces.size();
  188. mesh->mFaces = new aiFace[mesh->mNumFaces];
  189. // normals?
  190. if( sourceMesh->mNormals.size() > 0)
  191. mesh->mNormals = new aiVector3D[numVertices];
  192. // texture coords
  193. for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++)
  194. {
  195. if( sourceMesh->mTexCoords[c].size() > 0)
  196. mesh->mTextureCoords[c] = new aiVector3D[numVertices];
  197. }
  198. // vertex colors
  199. for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++)
  200. {
  201. if( sourceMesh->mColors[c].size() > 0)
  202. mesh->mColors[c] = new aiColor4D[numVertices];
  203. }
  204. // now collect the vertex data of all data streams present in the imported mesh
  205. unsigned int newIndex = 0;
  206. std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
  207. orgPoints.resize( numVertices, 0);
  208. for( unsigned int c = 0; c < faces.size(); c++)
  209. {
  210. unsigned int f = faces[c]; // index of the source face
  211. const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
  212. // create face. either triangle or triangle fan depending on the index count
  213. aiFace& df = mesh->mFaces[c]; // destination face
  214. df.mNumIndices = pf.mIndices.size();
  215. df.mIndices = new unsigned int[ df.mNumIndices];
  216. // collect vertex data for indices of this face
  217. for( unsigned int d = 0; d < df.mNumIndices; d++)
  218. {
  219. df.mIndices[df.mNumIndices - 1 - d] = newIndex; // inverted face orientation for OGL
  220. orgPoints[newIndex] = pf.mIndices[d];
  221. // Position
  222. mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
  223. // Normal, if present
  224. if( mesh->HasNormals())
  225. mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]];
  226. // texture coord sets
  227. for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++)
  228. {
  229. if( mesh->HasTextureCoords( e))
  230. {
  231. aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
  232. mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
  233. }
  234. }
  235. // vertex color sets
  236. for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++)
  237. if( mesh->HasVertexColors( e))
  238. mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
  239. newIndex++;
  240. }
  241. }
  242. // there should be as much new vertices as we calculated before
  243. assert( newIndex == numVertices);
  244. // convert all bones of the source mesh which influence vertices in this newly created mesh
  245. const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
  246. std::vector<aiBone*> newBones;
  247. for( unsigned int c = 0; c < bones.size(); c++)
  248. {
  249. const XFile::Bone& obone = bones[c];
  250. // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
  251. std::vector<float> oldWeights( sourceMesh->mPositions.size(), 0.0f);
  252. for( unsigned int d = 0; d < obone.mWeights.size(); d++)
  253. oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
  254. // collect all vertex weights that influence a vertex in the new mesh
  255. std::vector<aiVertexWeight> newWeights;
  256. newWeights.reserve( numVertices);
  257. for( unsigned int d = 0; d < orgPoints.size(); d++)
  258. {
  259. // does the new vertex stem from an old vertex which was influenced by this bone?
  260. float w = oldWeights[orgPoints[d]];
  261. if( w > 0.0f)
  262. newWeights.push_back( aiVertexWeight( d, w));
  263. }
  264. // if the bone has no weights in the newly created mesh, ignore it
  265. if( newWeights.size() == 0)
  266. continue;
  267. // create
  268. aiBone* nbone = new aiBone;
  269. newBones.push_back( nbone);
  270. // copy name and matrix
  271. nbone->mName.Set( obone.mName);
  272. nbone->mOffsetMatrix = obone.mOffsetMatrix;
  273. nbone->mNumWeights = newWeights.size();
  274. nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
  275. for( unsigned int d = 0; d < newWeights.size(); d++)
  276. nbone->mWeights[d] = newWeights[d];
  277. }
  278. // store the bones in the mesh
  279. mesh->mNumBones = newBones.size();
  280. mesh->mBones = new aiBone*[mesh->mNumBones];
  281. for( unsigned int c = 0; c < newBones.size(); c++)
  282. mesh->mBones[c] = newBones[c];
  283. }
  284. }
  285. // reallocate scene mesh array to be large enough
  286. aiMesh** prevArray = pScene->mMeshes;
  287. pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
  288. if( prevArray)
  289. {
  290. memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
  291. delete [] prevArray;
  292. }
  293. // allocate mesh index array in the node
  294. pNode->mNumMeshes = meshes.size();
  295. pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
  296. // store all meshes in the mesh library of the scene and store their indices in the node
  297. for( unsigned int a = 0; a < meshes.size(); a++)
  298. {
  299. pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
  300. pNode->mMeshes[a] = pScene->mNumMeshes;
  301. pScene->mNumMeshes++;
  302. }
  303. }
  304. // ------------------------------------------------------------------------------------------------
  305. // Converts the animations from the given imported data and creates them in the scene.
  306. void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData)
  307. {
  308. std::vector<aiAnimation*> newAnims;
  309. for( unsigned int a = 0; a < pData->mAnims.size(); a++)
  310. {
  311. const XFile::Animation* anim = pData->mAnims[a];
  312. // create a new animation to hold the data
  313. aiAnimation* nanim = new aiAnimation;
  314. newAnims.push_back( nanim);
  315. nanim->mName.Set( anim->mName);
  316. // duration will be determined by the maximum length
  317. nanim->mDuration = 0;
  318. nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
  319. nanim->mNumBones = anim->mAnims.size();
  320. nanim->mBones = new aiBoneAnim*[nanim->mNumBones];
  321. for( unsigned int b = 0; b < anim->mAnims.size(); b++)
  322. {
  323. const XFile::AnimBone* bone = anim->mAnims[b];
  324. aiBoneAnim* nbone = new aiBoneAnim;
  325. nbone->mBoneName.Set( bone->mBoneName);
  326. nanim->mBones[b] = nbone;
  327. // apply the LH->RH conversion if the animation affects the root bone
  328. bool isRootAnim = (bone->mBoneName == pScene->mRootNode->mName.data);
  329. // keyframes are given as combined transformation matrix keys
  330. if( bone->mTrafoKeys.size() > 0)
  331. {
  332. nbone->mNumPositionKeys = bone->mTrafoKeys.size();
  333. nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
  334. nbone->mNumRotationKeys = bone->mTrafoKeys.size();
  335. nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
  336. nbone->mNumScalingKeys = bone->mTrafoKeys.size();
  337. nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
  338. for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++)
  339. {
  340. // deconstruct each matrix into separate position, rotation and scaling
  341. double time = bone->mTrafoKeys[c].mTime;
  342. aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
  343. // extract position
  344. aiVector3D pos( trafo.a4, trafo.b4, trafo.c4);
  345. if( isRootAnim)
  346. ConvertToLHProcess::ConvertToOGL( pos);
  347. nbone->mPositionKeys[c].mTime = time;
  348. nbone->mPositionKeys[c].mValue = pos;
  349. // extract scaling
  350. aiVector3D scale;
  351. scale.x = aiVector3D( trafo.a1, trafo.b1, trafo.c1).Length();
  352. scale.y = aiVector3D( trafo.a2, trafo.b2, trafo.c2).Length();
  353. scale.z = aiVector3D( trafo.a3, trafo.b3, trafo.c3).Length();
  354. nbone->mScalingKeys[c].mTime = time;
  355. nbone->mScalingKeys[c].mValue = scale;
  356. // reconstruct rotation matrix without scaling
  357. aiMatrix3x3 rotmat(
  358. trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
  359. trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
  360. trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
  361. if( isRootAnim)
  362. ConvertToLHProcess::ConvertToOGL( rotmat);
  363. // and convert it into a quaternion
  364. nbone->mRotationKeys[c].mTime = time;
  365. nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
  366. }
  367. // longest lasting key sequence determines duration
  368. nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
  369. } else
  370. {
  371. // separate key sequences for position, rotation, scaling
  372. nbone->mNumPositionKeys = bone->mPosKeys.size();
  373. nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
  374. for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++)
  375. {
  376. aiVector3D pos = bone->mPosKeys[c].mValue;
  377. if( isRootAnim)
  378. ConvertToLHProcess::ConvertToOGL( pos);
  379. nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
  380. nbone->mPositionKeys[c].mValue = pos;
  381. }
  382. // rotation
  383. nbone->mNumRotationKeys = bone->mRotKeys.size();
  384. nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
  385. for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++)
  386. {
  387. aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
  388. if( isRootAnim)
  389. ConvertToLHProcess::ConvertToOGL( rotmat);
  390. nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
  391. nbone->mRotationKeys[c].mValue = aiQuaternion( rotmat);
  392. }
  393. // scaling
  394. nbone->mNumScalingKeys = bone->mScaleKeys.size();
  395. nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
  396. for( unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
  397. nbone->mScalingKeys[c] = bone->mScaleKeys[c];
  398. // longest lasting key sequence determines duration
  399. if( bone->mPosKeys.size() > 0)
  400. nanim->mDuration = std::max( nanim->mDuration, bone->mPosKeys.back().mTime);
  401. if( bone->mRotKeys.size() > 0)
  402. nanim->mDuration = std::max( nanim->mDuration, bone->mRotKeys.back().mTime);
  403. if( bone->mScaleKeys.size() > 0)
  404. nanim->mDuration = std::max( nanim->mDuration, bone->mScaleKeys.back().mTime);
  405. }
  406. }
  407. }
  408. // store all converted animations in the scene
  409. if( newAnims.size() > 0)
  410. {
  411. pScene->mNumAnimations = newAnims.size();
  412. pScene->mAnimations = new aiAnimation* [pScene->mNumAnimations];
  413. for( unsigned int a = 0; a < newAnims.size(); a++)
  414. pScene->mAnimations[a] = newAnims[a];
  415. }
  416. }
  417. // ------------------------------------------------------------------------------------------------
  418. // Converts all materials in the given array and stores them in the scene's material list.
  419. void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vector<XFile::Material>& pMaterials)
  420. {
  421. // count the non-referrer materials in the array
  422. unsigned int numMaterials = 0;
  423. for( unsigned int a = 0; a < pMaterials.size(); a++)
  424. if( !pMaterials[a].mIsReference)
  425. numMaterials++;
  426. if( numMaterials == 0)
  427. return;
  428. // resize the scene's material list to offer enough space for the new materials
  429. aiMaterial** prevMats = pScene->mMaterials;
  430. pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numMaterials];
  431. if( prevMats)
  432. {
  433. memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
  434. delete [] prevMats;
  435. }
  436. // convert all the materials given in the array
  437. for( unsigned int a = 0; a < pMaterials.size(); a++)
  438. {
  439. const XFile::Material& oldMat = pMaterials[a];
  440. if( oldMat.mIsReference)
  441. continue;
  442. Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
  443. aiString name;
  444. name.Set( oldMat.mName);
  445. mat->AddProperty( &name, AI_MATKEY_NAME);
  446. // Shading model: hardcoded to PHONG, there is no such information in an XFile
  447. int shadeMode = (int) aiShadingMode_Phong;
  448. mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
  449. // material colours
  450. mat->AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  451. mat->AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  452. mat->AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
  453. mat->AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
  454. // texture, if there is one
  455. if (1 == oldMat.mTextures.size())
  456. {
  457. // if there is only one texture, assume it contains the
  458. // diffuse color
  459. aiString tex;
  460. tex.Set( oldMat.mTextures[0]);
  461. mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
  462. }
  463. else
  464. {
  465. // Otherwise ... try to search for typical strings in the
  466. // texture's file name like 'bump' or 'diffuse'
  467. unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
  468. for( unsigned int b = 0; b < oldMat.mTextures.size(); b++)
  469. {
  470. std::string sz = oldMat.mTextures[b];
  471. char key[256];
  472. // find the file name
  473. const size_t iLen = sz.length();
  474. std::string::size_type s = sz.rfind('\\',iLen-1);
  475. if (std::string::npos == s)
  476. {
  477. s = sz.rfind('/',iLen-1);
  478. if (std::string::npos == s)s = 0;
  479. }
  480. // cut off the file extension
  481. std::string::size_type sExt = sz.rfind('.',iLen-1);
  482. if (std::string::npos != sExt)
  483. {
  484. sz[sExt] = '\0';
  485. }
  486. // bump map
  487. std::string::size_type s2 = sz.find("bump",s);
  488. if (std::string::npos == s2)
  489. {
  490. s2 = sz.find("BUMP",s);
  491. if (std::string::npos == s2)
  492. {
  493. s2 = sz.find("Bump",s);
  494. if (std::string::npos == s2)
  495. {
  496. s2 = sz.find("height",s);
  497. if (std::string::npos == s2)
  498. {
  499. s2 = sz.find("HEIGHT",s);
  500. if (std::string::npos == s2)
  501. {
  502. s2 = sz.find("Height",s);
  503. }
  504. }
  505. }
  506. }
  507. }
  508. if (std::string::npos != s2)
  509. {
  510. sprintf(key,AI_MATKEY_TEXTURE_BUMP_ "[%i]",iHM++);
  511. }
  512. else
  513. {
  514. // Normal map
  515. std::string::size_type s2 = sz.find("normal",s);
  516. if (std::string::npos == s2)
  517. {
  518. s2 = sz.find("NORMAL",s);
  519. if (std::string::npos == s2)
  520. {
  521. s2 = sz.find("nm",s); // not really unique
  522. if (std::string::npos == s2)
  523. {
  524. s2 = sz.find("Normal",s);
  525. if (std::string::npos == s2)
  526. {
  527. s2 = sz.find("NM",s);
  528. }
  529. }
  530. }
  531. }
  532. if (std::string::npos != s2)
  533. {
  534. sprintf(key,AI_MATKEY_TEXTURE_NORMALS_ "[%i]",iNM++);
  535. }
  536. else
  537. {
  538. // specular color texture (not unique, too. Could
  539. // also be the material's shininess)
  540. std::string::size_type s2 = sz.find("spec",s);
  541. if (std::string::npos == s2)
  542. {
  543. s2 = sz.find("Spec",s);
  544. if (std::string::npos == s2)
  545. {
  546. s2 = sz.find("SPEC",s);
  547. if (std::string::npos == s2)
  548. {
  549. s2 = sz.find("Glanz",s);
  550. if (std::string::npos == s2)
  551. {
  552. s2 = sz.find("glanz",s);
  553. }
  554. }
  555. }
  556. }
  557. if (std::string::npos != s2)
  558. {
  559. sprintf(key,AI_MATKEY_TEXTURE_SPECULAR_ "[%i]",iSM++);
  560. }
  561. else
  562. {
  563. // ambient color texture
  564. std::string::size_type s2 = sz.find("ambi",s);
  565. if (std::string::npos == s2)
  566. {
  567. s2 = sz.find("AMBI",s);
  568. if (std::string::npos == s2)
  569. {
  570. s2 = sz.find("umgebungsfarbe",s);
  571. if (std::string::npos == s2)
  572. {
  573. s2 = sz.find("Ambi",s);
  574. }
  575. }
  576. }
  577. if (std::string::npos != s2)
  578. {
  579. sprintf(key,AI_MATKEY_TEXTURE_AMBIENT_ "[%i]",iAM++);
  580. }
  581. else
  582. {
  583. // emissive color texture
  584. std::string::size_type s2 = sz.find("emissive",s);
  585. if (std::string::npos == s2)
  586. {
  587. s2 = sz.find("EMISSIVE",s);
  588. if (std::string::npos == s2)
  589. {
  590. // self illumination
  591. s2 = sz.find("self",s);
  592. if (std::string::npos == s2)
  593. {
  594. s2 = sz.find("Emissive",s);
  595. }
  596. }
  597. }
  598. if (std::string::npos != s2)
  599. {
  600. sprintf(key,AI_MATKEY_TEXTURE_EMISSIVE_ "[%i]",iEM++);
  601. }
  602. else
  603. {
  604. // assume it is a diffuse texture
  605. sprintf(key,AI_MATKEY_TEXTURE_DIFFUSE_ "[%i]",iDM++);
  606. }
  607. }
  608. }
  609. }
  610. }
  611. aiString tex;
  612. tex.Set( oldMat.mTextures[b] );
  613. mat->AddProperty( &tex, key);
  614. }
  615. }
  616. pScene->mMaterials[pScene->mNumMaterials] = mat;
  617. mImportedMats[oldMat.mName] = pScene->mNumMaterials;
  618. pScene->mNumMaterials++;
  619. }
  620. }