// static bool OBJLoader::parseOBJ( QString objFilename, std::shared_ptr< OBJData > pOBJData ) { // attempt to read the file QFile inputFile( objFilename ); if( !( inputFile.open( QIODevice::ReadOnly ) ) ) { return false; } int lineNumber = 0; QString line = ""; OBJGroup* pCurrentGroup = pOBJData->getGroupByName( "" ); // default group name is the empty string QTextStream inputTextStream( &inputFile ); QString delim( " " ); line = inputTextStream.readLine(); while( !( line.isNull() ) ) { if( line != "" ) { QStringList tokens = line.split( delim, QString::SkipEmptyParts ); if( tokens.size() > 0 ) { QString commandToken = tokens[ 0 ]; if( commandToken == "mtllib" ) { QString mtlRelativeFilename = tokens[ 1 ]; QFileInfo objFileInfo( objFilename ); QDir objDir = objFileInfo.dir(); QString mtlAbsoluteFilename = objDir.absolutePath() + "/" + mtlRelativeFilename; parseMTL( mtlAbsoluteFilename, pOBJData ); } else if( commandToken == "g" ) { QString newGroupName; if( tokens.size() < 2 ) { fprintf( stderr, "Warning: group has no name, defaulting to ""\nline: %d\n%s", lineNumber, qPrintable( line ) ); newGroupName = ""; } else { newGroupName = tokens[ 1 ]; } if( newGroupName != pCurrentGroup->name() ) { if( pOBJData->containsGroup( newGroupName ) ) { pCurrentGroup = pOBJData->getGroupByName( newGroupName ); } else { pCurrentGroup = pOBJData->addGroup( newGroupName ); } } } else if( commandToken == "v" ) { // TODO: error checking on all of these and tear down pOBJData OBJLoader::parsePosition( lineNumber, line, tokens, pOBJData ); } else if( commandToken == "vt" ) { OBJLoader::parseTextureCoordinate( lineNumber, line, tokens, pOBJData ); } else if( commandToken == "vn" ) { OBJLoader::parseNormal( lineNumber, line, tokens, pOBJData ); } else if( commandToken == "usemtl" ) { pCurrentGroup->addMaterial( tokens[ 1 ] ); } else if( commandToken == "f" || commandToken == "fo" ) { OBJLoader::parseFace( lineNumber, line, tokens, pCurrentGroup ); } } } ++lineNumber; line = inputTextStream.readLine(); } return true; }
// static bool OBJLoader::parseFace( int lineNumber, const std::string& line, const std::vector< std::string >& tokens, OBJGroup& currentGroup ) { // TODO: support negative indices. if( tokens.size() < 4 ) { fprintf( stderr, "Incorrect number of tokens at line number: %d\n, %s\n", lineNumber, line.c_str() ); return false; } // first check line consistency - each vertex in the face // should have the same number of attributes bool faceIsValid; bool faceHasTextureCoordinates; bool faceHasNormals; faceIsValid = OBJLoader::faceHasConsistentAttributes( tokens, &faceHasTextureCoordinates, &faceHasNormals ); if( !faceIsValid ) { fprintf( stderr, "Face attributes inconsistent at line number: %d\n%s\n", lineNumber, line.c_str() ); return false; } // ensure that all faces in a group are consistent: // they either all have texture coordinates or they don't // they either all have normals or they don't // // check how many faces the current group has // if the group has no faces, then the first face sets the group attributes if( currentGroup.numFaces() == 0 ) { currentGroup.setHasTextureCoordinates( faceHasTextureCoordinates ); currentGroup.setHasNormals( faceHasNormals ); } bool faceIsConsistentWithGroup = ( currentGroup.hasTextureCoordinates() == faceHasTextureCoordinates ) && ( currentGroup.hasNormals() == faceHasNormals ); if( !faceIsConsistentWithGroup ) { // TODO: boolToString() fprintf( stderr, "Face attributes inconsistent with group: %s at line: %d\n%s\n", currentGroup.name().c_str(), lineNumber, line.c_str() ); fprintf( stderr, "group.hasTextureCoordinates() = %d\n", currentGroup.hasTextureCoordinates() ); fprintf( stderr, "face.hasTextureCoordinates() = %d\n", faceHasTextureCoordinates ); fprintf( stderr, "group.hasNormals() = %d\n", currentGroup.hasNormals() ); fprintf( stderr, "face.hasNormals() = %d\n", faceHasNormals ); return false; } OBJFace face( faceHasTextureCoordinates, faceHasNormals ); // Process each vertex. for( int i = 1; i < tokens.size(); ++i ) { int vertexPositionIndex; int vertexTextureCoordinateIndex; int vertexNormalIndex; OBJLoader::getVertexAttributes( tokens[ i ], &vertexPositionIndex, &vertexTextureCoordinateIndex, &vertexNormalIndex ); face.positionIndices().push_back( vertexPositionIndex - 1 ); if( faceHasTextureCoordinates ) { face.textureCoordinateIndices().push_back( vertexTextureCoordinateIndex - 1 ); } if( faceHasNormals ) { face.normalIndices().push_back( vertexNormalIndex - 1 ); } } currentGroup.addFace( face ); return true; }