diff options
author | Andy Maloney <asmaloney@gmail.com> | 2013-08-04 15:11:18 -0400 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-05 17:29:10 +0200 |
commit | a7a8209a2fe8b81b927376ef6806a6662aa91102 (patch) | |
tree | 2e370bd41cd9ee59505f47244364cf209a9944f6 | |
parent | 78e7783a237b8cfc3491aaad04bda5fe9568106e (diff) | |
download | qt3d-a7a8209a2fe8b81b927376ef6806a6662aa91102.tar.gz |
Cherry pick OBJ fixes from current Assimp (3.x)
Fixes multiple issues, add consts, better error output, and allow spaces in names
Change-Id: I9084ec7861ad0c71977c765da7c132ba75bbc46b
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: James Turner <james.turner@kdab.com>
-rwxr-xr-x[-rw-r--r--] | 3rdparty/assimp/code/ObjFileImporter.cpp | 16 | ||||
-rw-r--r-- | 3rdparty/assimp/code/ObjFileMtlImporter.cpp | 26 | ||||
-rwxr-xr-x[-rw-r--r--] | 3rdparty/assimp/code/ObjFileParser.cpp | 60 | ||||
-rw-r--r-- | 3rdparty/assimp/code/ObjTools.h | 49 |
4 files changed, 112 insertions, 39 deletions
diff --git a/3rdparty/assimp/code/ObjFileImporter.cpp b/3rdparty/assimp/code/ObjFileImporter.cpp index 5c8680f2f..9556bf413 100644..100755 --- a/3rdparty/assimp/code/ObjFileImporter.cpp +++ b/3rdparty/assimp/code/ObjFileImporter.cpp @@ -188,6 +188,8 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile aiNode *pNode = new aiNode; pNode->mName = aiString(pObject->m_strObjName); + pNode->mName = pObject->m_strObjName; + if (pParent != NULL) appendChildToParentNode(pParent, pNode); @@ -334,14 +336,18 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, for ( size_t vertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ ) { const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex ); - ai_assert( vertex < pModel->m_Vertices.size() ); + if ( vertex >= pModel->m_Vertices.size() ) + throw DeadlyImportError( "OBJ: vertex index out of range" ); + pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ]; // Copy all normals - if ( !pSourceFace->m_pNormals->empty() ) + if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty() ) { const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex ); - ai_assert( normal < pModel->m_Normals.size() ); + if ( normal >= pModel->m_Normals.size() ) + throw DeadlyImportError("OBJ: vertex normal index out of range"); + pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ]; } @@ -401,8 +407,10 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size(); pScene->mNumMaterials = 0; if ( pModel->m_MaterialLib.empty() ) + { + DefaultLogger::get()->debug("OBJ: no materials specified"); return; - + } pScene->mMaterials = new aiMaterial*[ numMaterials ]; for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ ) { diff --git a/3rdparty/assimp/code/ObjFileMtlImporter.cpp b/3rdparty/assimp/code/ObjFileMtlImporter.cpp index fff5b224f..2dd89ac83 100644 --- a/3rdparty/assimp/code/ObjFileMtlImporter.cpp +++ b/3rdparty/assimp/code/ObjFileMtlImporter.cpp @@ -223,19 +223,29 @@ void ObjFileMtlImporter::getFloatValue( float &value ) // Creates a material from loaded data. void ObjFileMtlImporter::createMaterial() { - std::string strName( "" ); - m_DataIt = getName<DataArrayIt>( m_DataIt, m_DataItEnd, strName ); - if ( m_DataItEnd == m_DataIt ) - return; + std::string line( "" ); + while ( !isNewLine( *m_DataIt ) ) { + line += *m_DataIt; + ++m_DataIt; + } + + std::vector<std::string> token; + const unsigned int numToken = tokenize<std::string>( line, token, " " ); + std::string name( "" ); + if ( numToken == 1 ) { + name = AI_DEFAULT_MATERIAL_NAME; + } else { + name = token[ 1 ]; + } - std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName ); + std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( name ); if ( m_pModel->m_MaterialMap.end() == it) { // New Material created m_pModel->m_pCurrentMaterial = new ObjFile::Material(); - m_pModel->m_pCurrentMaterial->MaterialName.Set( strName ); - m_pModel->m_MaterialLib.push_back( strName ); - m_pModel->m_MaterialMap[ strName ] = m_pModel->m_pCurrentMaterial; + m_pModel->m_pCurrentMaterial->MaterialName.Set( name ); + m_pModel->m_MaterialLib.push_back( name ); + m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial; } else { diff --git a/3rdparty/assimp/code/ObjFileParser.cpp b/3rdparty/assimp/code/ObjFileParser.cpp index 7f1bd0bd7..03a1caa27 100644..100755 --- a/3rdparty/assimp/code/ObjFileParser.cpp +++ b/3rdparty/assimp/code/ObjFileParser.cpp @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ObjFileMtlImporter.h" #include "ObjTools.h" #include "ObjFileData.h" +#include "ParsingUtils.h" #include "fast_atof.h" #include "../include/aiTypes.h" #include "DefaultIOSystem.h" @@ -70,6 +71,8 @@ ObjFileParser::ObjFileParser(std::vector<char> &Data,const std::string &strModel m_uiLine(0), m_pIO( io ) { + std::fill_n(m_buffer,BUFFERSIZE,0); + // Create the model instance to store all the data m_pModel = new ObjFile::Model(); m_pModel->m_ModelName = strModelName; @@ -192,7 +195,7 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { size_t index = 0; m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd); - while ( !isSeparator(*m_DataIt) && m_DataIt != m_DataItEnd ) + while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) ) { pBuffer[index] = *m_DataIt; index++; @@ -266,7 +269,7 @@ void ObjFileParser::getFace() char *pPtr = m_buffer; char *pEnd = &pPtr[BUFFERSIZE]; pPtr = getNextToken<char*>(pPtr, pEnd); - if (pPtr == '\0') + if (pPtr == pEnd || *pPtr == '\0') return; std::vector<unsigned int> *pIndices = new std::vector<unsigned int>; @@ -274,8 +277,8 @@ void ObjFileParser::getFace() std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>; bool hasNormal = false; - bool vt = (!m_pModel->m_TextureCoord.empty()); - bool vn = (!m_pModel->m_Normals.empty()); + const bool vt = (!m_pModel->m_TextureCoord.empty()); + const bool vn = (!m_pModel->m_Normals.empty()); int iStep = 0, iPos = 0; while (pPtr != pEnd) { @@ -283,7 +286,7 @@ void ObjFileParser::getFace() if (*pPtr == '\0') break; - if (*pPtr=='\r') + if (IsLineEnd(*pPtr)) break; if (*pPtr=='/' ) @@ -332,8 +335,14 @@ void ObjFileParser::getFace() } } } - for ( int i=0; i<iStep; i++ ) - ++pPtr; + pPtr += iStep; + } + + if ( pIndices->empty() ) + { + DefaultLogger::get()->error("Obj: Ignoring empty face"); + m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); + return; } ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID ); @@ -370,13 +379,22 @@ void ObjFileParser::getFace() // Get values for a new material description void ObjFileParser::getMaterialDesc() { + // Each material request a new object. + // Sometimes the object is already created (see 'o' tag by example), but it is not initialized ! + // So, we create a new object only if the current on is already initialized ! + if (m_pModel->m_pCurrent != NULL && + (m_pModel->m_pCurrent->m_Meshes.size() > 1 || + (m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0)) + ) + m_pModel->m_pCurrent = NULL; + // Get next data for material data m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); if (m_DataIt == m_DataItEnd) return; char *pStart = &(*m_DataIt); - while ( !isSeparator(*m_DataIt) && m_DataIt != m_DataItEnd ) + while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) ) ++m_DataIt; // Get name @@ -390,6 +408,7 @@ void ObjFileParser::getMaterialDesc() { // Not found, use default material m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; + DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); } else { @@ -410,10 +429,9 @@ void ObjFileParser::getMaterialDesc() // Get a comment, values will be skipped void ObjFileParser::getComment() { - bool running = true; - while (running) + while (m_DataIt != m_DataItEnd) { - if ( '\n' == (*m_DataIt) || m_DataIt == m_DataItEnd ) + if ( '\n' == (*m_DataIt) ) { ++m_DataIt; break; @@ -435,7 +453,7 @@ void ObjFileParser::getMaterialLib() return; char *pStart = &(*m_DataIt); - while (!isNewLine(*m_DataIt)) + while (m_DataIt != m_DataItEnd && !isNewLine(*m_DataIt)) m_DataIt++; // Check for existence @@ -469,7 +487,7 @@ void ObjFileParser::getNewMaterial() char *pStart = &(*m_DataIt); std::string strMat( pStart, *m_DataIt ); - while ( isSeparator( *m_DataIt ) ) + while ( m_DataIt != m_DataItEnd && isSeparator( *m_DataIt ) ) m_DataIt++; std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat ); if ( it == m_pModel->m_MaterialMap.end() ) @@ -512,17 +530,11 @@ int ObjFileParser::getMaterialIndex( const std::string &strMaterialName ) // Getter for a group name. void ObjFileParser::getGroupName() { - // Get next word from data buffer - m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); - m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd); - if ( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) - return; + std::string strGroupName; - // Store groupname in group library - char *pStart = &(*m_DataIt); - while ( !isSeparator(*m_DataIt) ) - m_DataIt++; - std::string strGroupName(pStart, &(*m_DataIt)); + m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName); + if ( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) + return; // Change active group, if necessary if ( m_pModel->m_strActiveGroup != strGroupName ) @@ -567,7 +579,7 @@ void ObjFileParser::getObjectName() if (m_DataIt == m_DataItEnd) return; char *pStart = &(*m_DataIt); - while ( !isSeparator( *m_DataIt ) ) + while ( m_DataIt != m_DataItEnd && !isSeparator( *m_DataIt ) ) ++m_DataIt; std::string strObjectName(pStart, &(*m_DataIt)); diff --git a/3rdparty/assimp/code/ObjTools.h b/3rdparty/assimp/code/ObjTools.h index 96c339e50..6f0016f29 100644 --- a/3rdparty/assimp/code/ObjTools.h +++ b/3rdparty/assimp/code/ObjTools.h @@ -146,7 +146,8 @@ inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) return it; } -/** @brief Get a name, must be separated with a blank. +/** @brief Get a name from the current line. Preserve space in the middle, + * but trim it at the end. * @param it set to current position * @param end set to end of scratch buffer for readout * @param name Separated name @@ -161,10 +162,20 @@ inline char_t getName( char_t it, char_t end, std::string &name ) return end; char *pStart = &( *it ); - while ( !isEndOfBuffer( it, end ) && !isSeparator( *it ) ) - ++it; + while ( !isEndOfBuffer( it, end ) && !isNewLine( *it ) ) { + ++it; + } + + while (isEndOfBuffer( it, end ) || isNewLine( *it ) || isSeparator(*it)) { + --it; + } + ++it; // Get name + // if there is no name, and the previous char is a separator, come back to start + while (&(*it) < pStart) { + ++it; + } std::string strName( pStart, &(*it) ); if ( strName.empty() ) return it; @@ -215,6 +226,38 @@ inline char_t getFloat( char_t it, char_t end, float &value ) return it; } +/** @brief Will perform a simple tokenize. + * @param str String to tokenize. + * @param tokens Array with tokens, will be empty if no token was found. + * @param delimiters Delimiter for tokenize. + * @return Number of found token. + */ +template<class string_type> +unsigned int tokenize( const string_type& str, std::vector<string_type>& tokens, + const string_type& delimiters ) +{ + // Skip delimiters at beginning. + typename string_type::size_type lastPos = str.find_first_not_of( delimiters, 0 ); + + // Find first "non-delimiter". + typename string_type::size_type pos = str.find_first_of( delimiters, lastPos ); + while ( string_type::npos != pos || string_type::npos != lastPos ) + { + // Found a token, add it to the vector. + string_type tmp = str.substr(lastPos, pos - lastPos); + if ( !tmp.empty() && ' ' != tmp[ 0 ] ) + tokens.push_back( tmp ); + + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of( delimiters, pos ); + + // Find next "non-delimiter" + pos = str.find_first_of( delimiters, lastPos ); + } + + return static_cast<unsigned int>( tokens.size() ); +} + } // Namespace Assimp #endif |