1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2015, assimp team
7
8 All rights reserved.
9
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:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
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.
22
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.
27
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
42
43 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
44
45 #include "DefaultIOSystem.h"
46 #include "ObjFileImporter.h"
47 #include "ObjFileParser.h"
48 #include "ObjFileData.h"
49 #include <boost/scoped_ptr.hpp>
50 #include <assimp/Importer.hpp>
51 #include <assimp/scene.h>
52 #include <assimp/ai_assert.h>
53 #include <assimp/DefaultLogger.hpp>
54
55
56 static const aiImporterDesc desc = {
57 "Wavefront Object Importer",
58 "",
59 "",
60 "surfaces not supported",
61 aiImporterFlags_SupportTextFlavour,
62 0,
63 0,
64 0,
65 0,
66 "obj"
67 };
68
69 static const unsigned int ObjMinSize = 16;
70
71 namespace Assimp {
72
73 using namespace std;
74
75 // ------------------------------------------------------------------------------------------------
76 // Default constructor
ObjFileImporter()77 ObjFileImporter::ObjFileImporter() :
78 m_Buffer(),
79 m_pRootObject( NULL ),
80 m_strAbsPath( "" )
81 {
82 DefaultIOSystem io;
83 m_strAbsPath = io.getOsSeparator();
84 }
85
86 // ------------------------------------------------------------------------------------------------
87 // Destructor.
~ObjFileImporter()88 ObjFileImporter::~ObjFileImporter()
89 {
90 delete m_pRootObject;
91 m_pRootObject = NULL;
92 }
93
94 // ------------------------------------------------------------------------------------------------
95 // Returns true, if file is an obj file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const96 bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler , bool checkSig ) const
97 {
98 if(!checkSig) //Check File Extension
99 {
100 return SimpleExtensionCheck(pFile,"obj");
101 }
102 else //Check file Header
103 {
104 static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
105 return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 );
106 }
107 }
108
109 // ------------------------------------------------------------------------------------------------
GetInfo() const110 const aiImporterDesc* ObjFileImporter::GetInfo () const
111 {
112 return &desc;
113 }
114
115 // ------------------------------------------------------------------------------------------------
116 // Obj-file import implementation
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)117 void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
118 {
119 // Read file into memory
120 const std::string mode = "rb";
121 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
122 if( !file.get() ) {
123 throw DeadlyImportError( "Failed to open file " + pFile + "." );
124 }
125
126 // Get the file-size and validate it, throwing an exception when fails
127 size_t fileSize = file->FileSize();
128 if( fileSize < ObjMinSize ) {
129 throw DeadlyImportError( "OBJ-file is too small.");
130 }
131
132 // Allocate buffer and read file into it
133 TextFileToBuffer(file.get(),m_Buffer);
134
135 // Get the model name
136 std::string modelName, folderName;
137 std::string::size_type pos = pFile.find_last_of( "\\/" );
138 if ( pos != std::string::npos ) {
139 modelName = pFile.substr(pos+1, pFile.size() - pos - 1);
140 folderName = pFile.substr( 0, pos );
141 if ( !folderName.empty() ) {
142 pIOHandler->PushDirectory( folderName );
143 }
144 } else {
145 modelName = pFile;
146 }
147
148 // process all '\'
149 std::vector<char> ::iterator iter = m_Buffer.begin();
150 while (iter != m_Buffer.end())
151 {
152 if (*iter == '\\')
153 {
154 // remove '\'
155 iter = m_Buffer.erase(iter);
156 // remove next character
157 while (*iter == '\r' || *iter == '\n')
158 iter = m_Buffer.erase(iter);
159 }
160 else
161 ++iter;
162 }
163
164 // parse the file into a temporary representation
165 ObjFileParser parser(m_Buffer, modelName, pIOHandler);
166
167 // And create the proper return structures out of it
168 CreateDataFromImport(parser.GetModel(), pScene);
169
170 // Clean up allocated storage for the next import
171 m_Buffer.clear();
172
173 // Pop directory stack
174 if ( pIOHandler->StackSize() > 0 ) {
175 pIOHandler->PopDirectory();
176 }
177 }
178
179 // ------------------------------------------------------------------------------------------------
180 // Create the data from parsed obj-file
CreateDataFromImport(const ObjFile::Model * pModel,aiScene * pScene)181 void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene) {
182 if( 0L == pModel ) {
183 return;
184 }
185
186 // Create the root node of the scene
187 pScene->mRootNode = new aiNode;
188 if ( !pModel->m_ModelName.empty() )
189 {
190 // Set the name of the scene
191 pScene->mRootNode->mName.Set(pModel->m_ModelName);
192 }
193 else
194 {
195 // This is a fatal error, so break down the application
196 ai_assert(false);
197 }
198
199 // Create nodes for the whole scene
200 std::vector<aiMesh*> MeshArray;
201 for (size_t index = 0; index < pModel->m_Objects.size(); index++)
202 {
203 createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
204 }
205
206 // Create mesh pointer buffer for this scene
207 if (pScene->mNumMeshes > 0)
208 {
209 pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
210 for (size_t index =0; index < MeshArray.size(); index++)
211 {
212 pScene->mMeshes[ index ] = MeshArray[ index ];
213 }
214 }
215
216 // Create all materials
217 createMaterials( pModel, pScene );
218 }
219
220 // ------------------------------------------------------------------------------------------------
221 // Creates all nodes of the model
createNodes(const ObjFile::Model * pModel,const ObjFile::Object * pObject,aiNode * pParent,aiScene * pScene,std::vector<aiMesh * > & MeshArray)222 aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject,
223 aiNode *pParent, aiScene* pScene,
224 std::vector<aiMesh*> &MeshArray )
225 {
226 ai_assert( NULL != pModel );
227 if( NULL == pObject ) {
228 return NULL;
229 }
230
231 // Store older mesh size to be able to computes mesh offsets for new mesh instances
232 const size_t oldMeshSize = MeshArray.size();
233 aiNode *pNode = new aiNode;
234
235 pNode->mName = pObject->m_strObjName;
236
237 // If we have a parent node, store it
238 if( pParent != NULL ) {
239 appendChildToParentNode( pParent, pNode );
240 }
241
242 for ( size_t i=0; i< pObject->m_Meshes.size(); i++ )
243 {
244 unsigned int meshId = pObject->m_Meshes[ i ];
245 aiMesh *pMesh = createTopology( pModel, pObject, meshId );
246 if( pMesh && pMesh->mNumFaces > 0 ) {
247 MeshArray.push_back( pMesh );
248 }
249 }
250
251 // Create all nodes from the sub-objects stored in the current object
252 if ( !pObject->m_SubObjects.empty() )
253 {
254 size_t numChilds = pObject->m_SubObjects.size();
255 pNode->mNumChildren = static_cast<unsigned int>( numChilds );
256 pNode->mChildren = new aiNode*[ numChilds ];
257 pNode->mNumMeshes = 1;
258 pNode->mMeshes = new unsigned int[ 1 ];
259 }
260
261 // Set mesh instances into scene- and node-instances
262 const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
263 if ( meshSizeDiff > 0 )
264 {
265 pNode->mMeshes = new unsigned int[ meshSizeDiff ];
266 pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
267 size_t index = 0;
268 for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
269 {
270 pNode->mMeshes[ index ] = pScene->mNumMeshes;
271 pScene->mNumMeshes++;
272 index++;
273 }
274 }
275
276 return pNode;
277 }
278
279 // ------------------------------------------------------------------------------------------------
280 // Create topology data
createTopology(const ObjFile::Model * pModel,const ObjFile::Object * pData,unsigned int meshIndex)281 aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData,
282 unsigned int meshIndex )
283 {
284 // Checking preconditions
285 ai_assert( NULL != pModel );
286
287 if( NULL == pData ) {
288 return NULL;
289 }
290
291 // Create faces
292 ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ meshIndex ];
293 if( !pObjMesh ) {
294 return NULL;
295 }
296 ai_assert( NULL != pObjMesh );
297 aiMesh* pMesh = new aiMesh;
298 if( !pObjMesh->m_name.empty() ) {
299 pMesh->mName.Set( pObjMesh->m_name );
300 }
301
302 for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
303 {
304 ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
305 ai_assert( NULL != inp );
306
307 if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
308 pMesh->mNumFaces += inp->m_pVertices->size() - 1;
309 pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
310 } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
311 pMesh->mNumFaces += inp->m_pVertices->size();
312 pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
313 } else {
314 ++pMesh->mNumFaces;
315 if (inp->m_pVertices->size() > 3) {
316 pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
317 } else {
318 pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
319 }
320 }
321 }
322
323 unsigned int uiIdxCount( 0u );
324 if ( pMesh->mNumFaces > 0 ) {
325 pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
326 if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial ) {
327 pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
328 }
329
330 unsigned int outIndex( 0 );
331
332 // Copy all data from all stored meshes
333 for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
334 ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
335 if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
336 for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
337 aiFace& f = pMesh->mFaces[ outIndex++ ];
338 uiIdxCount += f.mNumIndices = 2;
339 f.mIndices = new unsigned int[2];
340 }
341 continue;
342 }
343 else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
344 for(size_t i = 0; i < inp->m_pVertices->size(); ++i) {
345 aiFace& f = pMesh->mFaces[ outIndex++ ];
346 uiIdxCount += f.mNumIndices = 1;
347 f.mIndices = new unsigned int[1];
348 }
349 continue;
350 }
351
352 aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
353 const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size();
354 uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
355 if (pFace->mNumIndices > 0) {
356 pFace->mIndices = new unsigned int[ uiNumIndices ];
357 }
358 }
359 }
360
361 // Create mesh vertices
362 createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount);
363
364 return pMesh;
365 }
366
367 // ------------------------------------------------------------------------------------------------
368 // Creates a vertex array
createVertexArray(const ObjFile::Model * pModel,const ObjFile::Object * pCurrentObject,unsigned int uiMeshIndex,aiMesh * pMesh,unsigned int numIndices)369 void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
370 const ObjFile::Object* pCurrentObject,
371 unsigned int uiMeshIndex,
372 aiMesh* pMesh,
373 unsigned int numIndices)
374 {
375 // Checking preconditions
376 ai_assert( NULL != pCurrentObject );
377
378 // Break, if no faces are stored in object
379 if ( pCurrentObject->m_Meshes.empty() )
380 return;
381
382 // Get current mesh
383 ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
384 if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1)
385 return;
386
387 // Copy vertices of this mesh instance
388 pMesh->mNumVertices = numIndices;
389 if (pMesh->mNumVertices == 0) {
390 throw DeadlyImportError( "OBJ: no vertices" );
391 } else if (pMesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
392 throw DeadlyImportError( "OBJ: Too many vertices, would run out of memory" );
393 }
394 pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
395
396 // Allocate buffer for normal vectors
397 if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals )
398 pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
399
400 // Allocate buffer for texture coordinates
401 if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] )
402 {
403 pMesh->mNumUVComponents[ 0 ] = 2;
404 pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ];
405 }
406
407 // Copy vertices, normals and textures into aiMesh instance
408 unsigned int newIndex = 0, outIndex = 0;
409 for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ )
410 {
411 // Get source face
412 ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ];
413
414 // Copy all index arrays
415 for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ )
416 {
417 const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex );
418 if ( vertex >= pModel->m_Vertices.size() )
419 throw DeadlyImportError( "OBJ: vertex index out of range" );
420
421 pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
422
423 // Copy all normals
424 if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size())
425 {
426 const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex );
427 if ( normal >= pModel->m_Normals.size() )
428 throw DeadlyImportError("OBJ: vertex normal index out of range");
429
430 pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ];
431 }
432
433 // Copy all texture coordinates
434 if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size())
435 {
436 const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex );
437 ai_assert( tex < pModel->m_TextureCoord.size() );
438
439 if ( tex >= pModel->m_TextureCoord.size() )
440 throw DeadlyImportError("OBJ: texture coordinate index out of range");
441
442 const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ];
443 pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
444 }
445
446 if ( pMesh->mNumVertices <= newIndex ) {
447 throw DeadlyImportError("OBJ: bad vertex index");
448 }
449
450 // Get destination face
451 aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
452
453 const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 );
454 if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last)
455 {
456 pDestFace->mIndices[ outVertexIndex ] = newIndex;
457 outVertexIndex++;
458 }
459
460 if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT)
461 {
462 outIndex++;
463 outVertexIndex = 0;
464 }
465 else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE)
466 {
467 outVertexIndex = 0;
468
469 if(!last)
470 outIndex++;
471
472 if (vertexIndex) {
473 if(!last) {
474 pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
475 if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) {
476 pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
477 }
478 if ( !pModel->m_TextureCoord.empty() ) {
479 for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) {
480 pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ];
481 }
482 }
483 ++newIndex;
484 }
485
486 pDestFace[-1].mIndices[1] = newIndex;
487 }
488 }
489 else if (last) {
490 outIndex++;
491 }
492 ++newIndex;
493 }
494 }
495 }
496
497 // ------------------------------------------------------------------------------------------------
498 // Counts all stored meshes
countObjects(const std::vector<ObjFile::Object * > & rObjects,int & iNumMeshes)499 void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
500 {
501 iNumMeshes = 0;
502 if ( rObjects.empty() )
503 return;
504
505 iNumMeshes += static_cast<unsigned int>( rObjects.size() );
506 for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
507 it != rObjects.end();
508 ++it)
509 {
510 if (!(*it)->m_SubObjects.empty())
511 {
512 countObjects((*it)->m_SubObjects, iNumMeshes);
513 }
514 }
515 }
516
517 // ------------------------------------------------------------------------------------------------
518 // Add clamp mode property to material if necessary
addTextureMappingModeProperty(aiMaterial * mat,aiTextureType type,int clampMode)519 void ObjFileImporter::addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode)
520 {
521 ai_assert( NULL != mat);
522 mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0));
523 mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0));
524 }
525
526 // ------------------------------------------------------------------------------------------------
527 // Creates the material
createMaterials(const ObjFile::Model * pModel,aiScene * pScene)528 void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pScene )
529 {
530 ai_assert( NULL != pScene );
531 if ( NULL == pScene )
532 return;
533
534 const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size();
535 pScene->mNumMaterials = 0;
536 if ( pModel->m_MaterialLib.empty() ) {
537 DefaultLogger::get()->debug("OBJ: no materials specified");
538 return;
539 }
540
541 pScene->mMaterials = new aiMaterial*[ numMaterials ];
542 for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ )
543 {
544 // Store material name
545 std::map<std::string, ObjFile::Material*>::const_iterator it;
546 it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
547
548 // No material found, use the default material
549 if ( pModel->m_MaterialMap.end() == it )
550 continue;
551
552 aiMaterial* mat = new aiMaterial;
553 ObjFile::Material *pCurrentMaterial = (*it).second;
554 mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
555
556 // convert illumination model
557 int sm = 0;
558 switch (pCurrentMaterial->illumination_model)
559 {
560 case 0:
561 sm = aiShadingMode_NoShading;
562 break;
563 case 1:
564 sm = aiShadingMode_Gouraud;
565 break;
566 case 2:
567 sm = aiShadingMode_Phong;
568 break;
569 default:
570 sm = aiShadingMode_Gouraud;
571 DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)");
572 }
573
574 mat->AddProperty<int>( &sm, 1, AI_MATKEY_SHADING_MODEL);
575
576 // multiplying the specular exponent with 2 seems to yield better results
577 pCurrentMaterial->shineness *= 4.f;
578
579 // Adding material colors
580 mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
581 mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
582 mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
583 mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE );
584 mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
585 mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
586
587 // Adding refraction index
588 mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI );
589
590 // Adding textures
591 if ( 0 != pCurrentMaterial->texture.length )
592 {
593 mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
594 if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType])
595 {
596 addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
597 }
598 }
599
600 if ( 0 != pCurrentMaterial->textureAmbient.length )
601 {
602 mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
603 if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType])
604 {
605 addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
606 }
607 }
608
609 if ( 0 != pCurrentMaterial->textureEmissive.length )
610 mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
611
612 if ( 0 != pCurrentMaterial->textureSpecular.length )
613 {
614 mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
615 if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType])
616 {
617 addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
618 }
619 }
620
621 if ( 0 != pCurrentMaterial->textureBump.length )
622 {
623 mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
624 if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType])
625 {
626 addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
627 }
628 }
629
630 if ( 0 != pCurrentMaterial->textureNormal.length )
631 {
632 mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
633 if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType])
634 {
635 addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
636 }
637 }
638
639 if( 0 != pCurrentMaterial->textureReflection[0].length )
640 {
641 ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
642 ObjFile::Material::TextureReflectionCubeTopType :
643 ObjFile::Material::TextureReflectionSphereType;
644
645 unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
646 for( unsigned i = 0; i < count; i++ )
647 mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
648
649 if(pCurrentMaterial->clamp[type])
650 //TODO addTextureMappingModeProperty should accept an index to handle clamp option for each
651 //texture of a cubemap
652 addTextureMappingModeProperty(mat, aiTextureType_REFLECTION);
653 }
654
655 if ( 0 != pCurrentMaterial->textureDisp.length )
656 {
657 mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
658 if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType])
659 {
660 addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
661 }
662 }
663
664 if ( 0 != pCurrentMaterial->textureOpacity.length )
665 {
666 mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
667 if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType])
668 {
669 addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
670 }
671 }
672
673 if ( 0 != pCurrentMaterial->textureSpecularity.length )
674 {
675 mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
676 if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType])
677 {
678 addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
679 }
680 }
681
682 // Store material property info in material array in scene
683 pScene->mMaterials[ pScene->mNumMaterials ] = mat;
684 pScene->mNumMaterials++;
685 }
686
687 // Test number of created materials.
688 ai_assert( pScene->mNumMaterials == numMaterials );
689 }
690
691 // ------------------------------------------------------------------------------------------------
692 // Appends this node to the parent node
appendChildToParentNode(aiNode * pParent,aiNode * pChild)693 void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
694 {
695 // Checking preconditions
696 ai_assert( NULL != pParent );
697 ai_assert( NULL != pChild );
698
699 // Assign parent to child
700 pChild->mParent = pParent;
701
702 // If already children was assigned to the parent node, store them in a
703 std::vector<aiNode*> temp;
704 if (pParent->mChildren != NULL)
705 {
706 ai_assert( 0 != pParent->mNumChildren );
707 for (size_t index = 0; index < pParent->mNumChildren; index++)
708 {
709 temp.push_back(pParent->mChildren [ index ] );
710 }
711 delete [] pParent->mChildren;
712 }
713
714 // Copy node instances into parent node
715 pParent->mNumChildren++;
716 pParent->mChildren = new aiNode*[ pParent->mNumChildren ];
717 for (size_t index = 0; index < pParent->mNumChildren-1; index++)
718 {
719 pParent->mChildren[ index ] = temp [ index ];
720 }
721 pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
722 }
723
724 // ------------------------------------------------------------------------------------------------
725
726 } // Namespace Assimp
727
728 #endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER
729