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 "ObjFileParser.h"
46 #include "ObjFileMtlImporter.h"
47 #include "ObjTools.h"
48 #include "ObjFileData.h"
49 #include "ParsingUtils.h"
50 #include "DefaultIOSystem.h"
51 #include "BaseImporter.h"
52 #include <assimp/DefaultLogger.hpp>
53 #include <assimp/material.h>
54 #include <assimp/Importer.hpp>
55 #include <cstdlib>
56
57
58 namespace Assimp {
59
60 const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
61
62 // -------------------------------------------------------------------
63 // Constructor with loaded data and directories.
ObjFileParser(std::vector<char> & data,const std::string & modelName,IOSystem * io)64 ObjFileParser::ObjFileParser(std::vector<char> &data,const std::string &modelName, IOSystem *io ) :
65 m_DataIt(data.begin()),
66 m_DataItEnd(data.end()),
67 m_pModel(NULL),
68 m_uiLine(0),
69 m_pIO( io )
70 {
71 std::fill_n(m_buffer,Buffersize,0);
72
73 // Create the model instance to store all the data
74 m_pModel = new ObjFile::Model();
75 m_pModel->m_ModelName = modelName;
76
77 // create default material and store it
78 m_pModel->m_pDefaultMaterial = new ObjFile::Material;
79 m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL );
80 m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL );
81 m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
82
83 // Start parsing the file
84 parseFile();
85 }
86
87 // -------------------------------------------------------------------
88 // Destructor
~ObjFileParser()89 ObjFileParser::~ObjFileParser()
90 {
91 delete m_pModel;
92 m_pModel = NULL;
93 }
94
95 // -------------------------------------------------------------------
96 // Returns a pointer to the model instance.
GetModel() const97 ObjFile::Model *ObjFileParser::GetModel() const
98 {
99 return m_pModel;
100 }
101
102 // -------------------------------------------------------------------
103 // File parsing method.
parseFile()104 void ObjFileParser::parseFile()
105 {
106 if (m_DataIt == m_DataItEnd)
107 return;
108
109 while (m_DataIt != m_DataItEnd)
110 {
111 switch (*m_DataIt)
112 {
113 case 'v': // Parse a vertex texture coordinate
114 {
115 ++m_DataIt;
116 if (*m_DataIt == ' ' || *m_DataIt == '\t') {
117 // read in vertex definition
118 getVector3(m_pModel->m_Vertices);
119 } else if (*m_DataIt == 't') {
120 // read in texture coordinate ( 2D or 3D )
121 ++m_DataIt;
122 getVector( m_pModel->m_TextureCoord );
123 } else if (*m_DataIt == 'n') {
124 // Read in normal vector definition
125 ++m_DataIt;
126 getVector3( m_pModel->m_Normals );
127 }
128 }
129 break;
130
131 case 'p': // Parse a face, line or point statement
132 case 'l':
133 case 'f':
134 {
135 getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l'
136 ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
137 }
138 break;
139
140 case '#': // Parse a comment
141 {
142 getComment();
143 }
144 break;
145
146 case 'u': // Parse a material desc. setter
147 {
148 getMaterialDesc();
149 }
150 break;
151
152 case 'm': // Parse a material library or merging group ('mg')
153 {
154 if (*(m_DataIt + 1) == 'g')
155 getGroupNumberAndResolution();
156 else
157 getMaterialLib();
158 }
159 break;
160
161 case 'g': // Parse group name
162 {
163 getGroupName();
164 }
165 break;
166
167 case 's': // Parse group number
168 {
169 getGroupNumber();
170 }
171 break;
172
173 case 'o': // Parse object name
174 {
175 getObjectName();
176 }
177 break;
178
179 default:
180 {
181 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
182 }
183 break;
184 }
185 }
186 }
187
188 // -------------------------------------------------------------------
189 // Copy the next word in a temporary buffer
copyNextWord(char * pBuffer,size_t length)190 void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
191 {
192 size_t index = 0;
193 m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
194 while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
195 pBuffer[index] = *m_DataIt;
196 index++;
197 if( index == length - 1 ) {
198 break;
199 }
200 ++m_DataIt;
201 }
202
203 ai_assert(index < length);
204 pBuffer[index] = '\0';
205 }
206
207 // -------------------------------------------------------------------
208 // Copy the next line into a temporary buffer
copyNextLine(char * pBuffer,size_t length)209 void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
210 {
211 size_t index = 0u;
212
213 // some OBJ files have line continuations using \ (such as in C++ et al)
214 bool continuation = false;
215 for (;m_DataIt != m_DataItEnd && index < length-1; ++m_DataIt)
216 {
217 const char c = *m_DataIt;
218 if (c == '\\') {
219 continuation = true;
220 continue;
221 }
222
223 if (c == '\n' || c == '\r') {
224 if(continuation) {
225 pBuffer[ index++ ] = ' ';
226 continue;
227 }
228 break;
229 }
230
231 continuation = false;
232 pBuffer[ index++ ] = c;
233 }
234 ai_assert(index < length);
235 pBuffer[ index ] = '\0';
236 }
237
238 // -------------------------------------------------------------------
getVector(std::vector<aiVector3D> & point3d_array)239 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
240 size_t numComponents( 0 );
241 const char* tmp( &m_DataIt[0] );
242 while( !IsLineEnd( *tmp ) ) {
243 if ( !SkipSpaces( &tmp ) ) {
244 break;
245 }
246 SkipToken( tmp );
247 ++numComponents;
248 }
249 float x, y, z;
250 if( 2 == numComponents ) {
251 copyNextWord( m_buffer, Buffersize );
252 x = ( float ) fast_atof( m_buffer );
253
254 copyNextWord( m_buffer, Buffersize );
255 y = ( float ) fast_atof( m_buffer );
256 z = 0.0;
257 } else if( 3 == numComponents ) {
258 copyNextWord( m_buffer, Buffersize );
259 x = ( float ) fast_atof( m_buffer );
260
261 copyNextWord( m_buffer, Buffersize );
262 y = ( float ) fast_atof( m_buffer );
263
264 copyNextWord( m_buffer, Buffersize );
265 z = ( float ) fast_atof( m_buffer );
266 } else {
267 throw DeadlyImportError( "OBJ: Invalid number of components" );
268 }
269 point3d_array.push_back( aiVector3D( x, y, z ) );
270 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
271 }
272
273 // -------------------------------------------------------------------
274 // Get values for a new 3D vector instance
getVector3(std::vector<aiVector3D> & point3d_array)275 void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
276 float x, y, z;
277 copyNextWord(m_buffer, Buffersize);
278 x = (float) fast_atof(m_buffer);
279
280 copyNextWord(m_buffer, Buffersize);
281 y = (float) fast_atof(m_buffer);
282
283 copyNextWord( m_buffer, Buffersize );
284 z = ( float ) fast_atof( m_buffer );
285
286 point3d_array.push_back( aiVector3D( x, y, z ) );
287 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
288 }
289
290 // -------------------------------------------------------------------
291 // Get values for a new 2D vector instance
getVector2(std::vector<aiVector2D> & point2d_array)292 void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
293 float x, y;
294 copyNextWord(m_buffer, Buffersize);
295 x = (float) fast_atof(m_buffer);
296
297 copyNextWord(m_buffer, Buffersize);
298 y = (float) fast_atof(m_buffer);
299
300 point2d_array.push_back(aiVector2D(x, y));
301
302 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
303 }
304
305 // -------------------------------------------------------------------
306 // Get values for a new face instance
getFace(aiPrimitiveType type)307 void ObjFileParser::getFace(aiPrimitiveType type)
308 {
309 copyNextLine(m_buffer, Buffersize);
310 if (m_DataIt == m_DataItEnd)
311 return;
312
313 char *pPtr = m_buffer;
314 char *pEnd = &pPtr[Buffersize];
315 pPtr = getNextToken<char*>(pPtr, pEnd);
316 if (pPtr == pEnd || *pPtr == '\0')
317 return;
318
319 std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
320 std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
321 std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
322 bool hasNormal = false;
323
324 const int vSize = m_pModel->m_Vertices.size();
325 const int vtSize = m_pModel->m_TextureCoord.size();
326 const int vnSize = m_pModel->m_Normals.size();
327
328 const bool vt = (!m_pModel->m_TextureCoord.empty());
329 const bool vn = (!m_pModel->m_Normals.empty());
330 int iStep = 0, iPos = 0;
331 while (pPtr != pEnd)
332 {
333 iStep = 1;
334
335 if (IsLineEnd(*pPtr))
336 break;
337
338 if (*pPtr=='/' )
339 {
340 if (type == aiPrimitiveType_POINT) {
341 DefaultLogger::get()->error("Obj: Separator unexpected in point statement");
342 }
343 if (iPos == 0)
344 {
345 //if there are no texture coordinates in the file, but normals
346 if (!vt && vn) {
347 iPos = 1;
348 iStep++;
349 }
350 }
351 iPos++;
352 }
353 else if( IsSpaceOrNewLine( *pPtr ) )
354 {
355 iPos = 0;
356 }
357 else
358 {
359 //OBJ USES 1 Base ARRAYS!!!!
360 const int iVal = atoi( pPtr );
361
362 // increment iStep position based off of the sign and # of digits
363 int tmp = iVal;
364 if (iVal < 0)
365 ++iStep;
366 while ( ( tmp = tmp / 10 )!=0 )
367 ++iStep;
368
369 if ( iVal > 0 )
370 {
371 // Store parsed index
372 if ( 0 == iPos )
373 {
374 pIndices->push_back( iVal-1 );
375 }
376 else if ( 1 == iPos )
377 {
378 pTexID->push_back( iVal-1 );
379 }
380 else if ( 2 == iPos )
381 {
382 pNormalID->push_back( iVal-1 );
383 hasNormal = true;
384 }
385 else
386 {
387 reportErrorTokenInFace();
388 }
389 }
390 else if ( iVal < 0 )
391 {
392 // Store relatively index
393 if ( 0 == iPos )
394 {
395 pIndices->push_back( vSize + iVal );
396 }
397 else if ( 1 == iPos )
398 {
399 pTexID->push_back( vtSize + iVal );
400 }
401 else if ( 2 == iPos )
402 {
403 pNormalID->push_back( vnSize + iVal );
404 hasNormal = true;
405 }
406 else
407 {
408 reportErrorTokenInFace();
409 }
410 }
411 }
412 pPtr += iStep;
413 }
414
415 if ( pIndices->empty() ) {
416 DefaultLogger::get()->error("Obj: Ignoring empty face");
417 // skip line and clean up
418 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
419 delete pNormalID;
420 delete pTexID;
421 delete pIndices;
422
423 return;
424 }
425
426 ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type );
427
428 // Set active material, if one set
429 if( NULL != m_pModel->m_pCurrentMaterial ) {
430 face->m_pMaterial = m_pModel->m_pCurrentMaterial;
431 } else {
432 face->m_pMaterial = m_pModel->m_pDefaultMaterial;
433 }
434
435 // Create a default object, if nothing is there
436 if( NULL == m_pModel->m_pCurrent ) {
437 createObject( "defaultobject" );
438 }
439
440 // Assign face to mesh
441 if ( NULL == m_pModel->m_pCurrentMesh ) {
442 createMesh( "defaultobject" );
443 }
444
445 // Store the face
446 m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
447 m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
448 m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
449 if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) {
450 m_pModel->m_pCurrentMesh->m_hasNormals = true;
451 }
452 // Skip the rest of the line
453 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
454 }
455
456 // -------------------------------------------------------------------
457 // Get values for a new material description
getMaterialDesc()458 void ObjFileParser::getMaterialDesc()
459 {
460 // Each material request a new object.
461 // Sometimes the object is already created (see 'o' tag by example), but it is not initialized !
462 // So, we create a new object only if the current on is already initialized !
463 if (m_pModel->m_pCurrent != NULL &&
464 ( m_pModel->m_pCurrent->m_Meshes.size() > 1 ||
465 (m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0) )
466 )
467 m_pModel->m_pCurrent = NULL;
468
469 // Get next data for material data
470 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
471 if (m_DataIt == m_DataItEnd) {
472 return;
473 }
474
475 char *pStart = &(*m_DataIt);
476 while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
477 ++m_DataIt;
478 }
479
480 // Get name
481 std::string strName(pStart, &(*m_DataIt));
482 if ( strName.empty())
483 return;
484
485 // Search for material
486 std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName );
487 if ( it == m_pModel->m_MaterialMap.end() ) {
488 // Not found, use default material
489 m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
490 DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping");
491 } else {
492 // Found, using detected material
493 m_pModel->m_pCurrentMaterial = (*it).second;
494 if ( needsNewMesh( strName ))
495 {
496 createMesh( strName );
497 }
498 m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
499 }
500
501 // Skip rest of line
502 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
503 }
504
505 // -------------------------------------------------------------------
506 // Get a comment, values will be skipped
getComment()507 void ObjFileParser::getComment()
508 {
509 while (m_DataIt != m_DataItEnd)
510 {
511 if ( '\n' == (*m_DataIt))
512 {
513 ++m_DataIt;
514 break;
515 }
516 else
517 {
518 ++m_DataIt;
519 }
520 }
521 }
522
523 // -------------------------------------------------------------------
524 // Get material library from file.
getMaterialLib()525 void ObjFileParser::getMaterialLib()
526 {
527 // Translate tuple
528 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
529 if( m_DataIt == m_DataItEnd ) {
530 return;
531 }
532
533 char *pStart = &(*m_DataIt);
534 while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
535 ++m_DataIt;
536 }
537
538 // Check for existence
539 const std::string strMatName(pStart, &(*m_DataIt));
540 std::string absName;
541 if ( m_pIO->StackSize() > 0 ) {
542 std::string path = m_pIO->CurrentDirectory();
543 if ( '/' != *path.rbegin() ) {
544 path += '/';
545 }
546 absName = path + strMatName;
547 } else {
548 absName = strMatName;
549 }
550 IOStream *pFile = m_pIO->Open( absName );
551
552 if (!pFile ) {
553 DefaultLogger::get()->error( "OBJ: Unable to locate material file " + strMatName );
554 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
555 return;
556 }
557
558 // Import material library data from file
559 std::vector<char> buffer;
560 BaseImporter::TextFileToBuffer( pFile, buffer );
561 m_pIO->Close( pFile );
562
563 // Importing the material library
564 ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel );
565 }
566
567 // -------------------------------------------------------------------
568 // Set a new material definition as the current material.
getNewMaterial()569 void ObjFileParser::getNewMaterial()
570 {
571 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
572 m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
573 if( m_DataIt == m_DataItEnd ) {
574 return;
575 }
576
577 char *pStart = &(*m_DataIt);
578 std::string strMat( pStart, *m_DataIt );
579 while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *m_DataIt ) ) {
580 ++m_DataIt;
581 }
582 std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
583 if ( it == m_pModel->m_MaterialMap.end() )
584 {
585 // Show a warning, if material was not found
586 DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
587 m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
588 }
589 else
590 {
591 // Set new material
592 if ( needsNewMesh( strMat ) )
593 {
594 createMesh( strMat );
595 }
596 m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
597 }
598
599 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
600 }
601
602 // -------------------------------------------------------------------
getMaterialIndex(const std::string & strMaterialName)603 int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
604 {
605 int mat_index = -1;
606 if( strMaterialName.empty() ) {
607 return mat_index;
608 }
609 for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
610 {
611 if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
612 {
613 mat_index = (int)index;
614 break;
615 }
616 }
617 return mat_index;
618 }
619
620 // -------------------------------------------------------------------
621 // Getter for a group name.
getGroupName()622 void ObjFileParser::getGroupName()
623 {
624 std::string strGroupName;
625
626 m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
627 if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
628 return;
629 }
630
631 // Change active group, if necessary
632 if ( m_pModel->m_strActiveGroup != strGroupName )
633 {
634 // Search for already existing entry
635 ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(strGroupName);
636
637 // We are mapping groups into the object structure
638 createObject( strGroupName );
639
640 // New group name, creating a new entry
641 if (it == m_pModel->m_Groups.end())
642 {
643 std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
644 m_pModel->m_Groups[ strGroupName ] = pFaceIDArray;
645 m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
646 }
647 else
648 {
649 m_pModel->m_pGroupFaceIDs = (*it).second;
650 }
651 m_pModel->m_strActiveGroup = strGroupName;
652 }
653 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
654 }
655
656 // -------------------------------------------------------------------
657 // Not supported
getGroupNumber()658 void ObjFileParser::getGroupNumber()
659 {
660 // Not used
661
662 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
663 }
664
665 // -------------------------------------------------------------------
666 // Not supported
getGroupNumberAndResolution()667 void ObjFileParser::getGroupNumberAndResolution()
668 {
669 // Not used
670
671 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
672 }
673
674 // -------------------------------------------------------------------
675 // Stores values for a new object instance, name will be used to
676 // identify it.
getObjectName()677 void ObjFileParser::getObjectName()
678 {
679 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
680 if( m_DataIt == m_DataItEnd ) {
681 return;
682 }
683 char *pStart = &(*m_DataIt);
684 while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
685 ++m_DataIt;
686 }
687
688 std::string strObjectName(pStart, &(*m_DataIt));
689 if (!strObjectName.empty())
690 {
691 // Reset current object
692 m_pModel->m_pCurrent = NULL;
693
694 // Search for actual object
695 for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin();
696 it != m_pModel->m_Objects.end();
697 ++it)
698 {
699 if ((*it)->m_strObjName == strObjectName)
700 {
701 m_pModel->m_pCurrent = *it;
702 break;
703 }
704 }
705
706 // Allocate a new object, if current one was not found before
707 if( NULL == m_pModel->m_pCurrent ) {
708 createObject( strObjectName );
709 }
710 }
711 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
712 }
713 // -------------------------------------------------------------------
714 // Creates a new object instance
createObject(const std::string & objName)715 void ObjFileParser::createObject(const std::string &objName)
716 {
717 ai_assert( NULL != m_pModel );
718
719 m_pModel->m_pCurrent = new ObjFile::Object;
720 m_pModel->m_pCurrent->m_strObjName = objName;
721 m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
722
723 createMesh( objName );
724
725 if( m_pModel->m_pCurrentMaterial )
726 {
727 m_pModel->m_pCurrentMesh->m_uiMaterialIndex =
728 getMaterialIndex( m_pModel->m_pCurrentMaterial->MaterialName.data );
729 m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
730 }
731 }
732 // -------------------------------------------------------------------
733 // Creates a new mesh
createMesh(const std::string & meshName)734 void ObjFileParser::createMesh( const std::string &meshName )
735 {
736 ai_assert( NULL != m_pModel );
737 m_pModel->m_pCurrentMesh = new ObjFile::Mesh( meshName );
738 m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
739 unsigned int meshId = m_pModel->m_Meshes.size()-1;
740 if ( NULL != m_pModel->m_pCurrent )
741 {
742 m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
743 }
744 else
745 {
746 DefaultLogger::get()->error("OBJ: No object detected to attach a new mesh instance.");
747 }
748 }
749
750 // -------------------------------------------------------------------
751 // Returns true, if a new mesh must be created.
needsNewMesh(const std::string & rMaterialName)752 bool ObjFileParser::needsNewMesh( const std::string &rMaterialName )
753 {
754 if(m_pModel->m_pCurrentMesh == 0)
755 {
756 // No mesh data yet
757 return true;
758 }
759 bool newMat = false;
760 int matIdx = getMaterialIndex( rMaterialName );
761 int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
762 if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) || curMatIdx != matIdx )
763 {
764 // New material -> only one material per mesh, so we need to create a new
765 // material
766 newMat = true;
767 }
768 return newMat;
769 }
770
771 // -------------------------------------------------------------------
772 // Shows an error in parsing process.
reportErrorTokenInFace()773 void ObjFileParser::reportErrorTokenInFace()
774 {
775 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
776 DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
777 }
778
779 // -------------------------------------------------------------------
780
781 } // Namespace Assimp
782
783 #endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER
784