vrshoot

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