summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Maloney <asmaloney@gmail.com>2013-08-04 15:11:18 -0400
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-05 17:29:10 +0200
commita7a8209a2fe8b81b927376ef6806a6662aa91102 (patch)
tree2e370bd41cd9ee59505f47244364cf209a9944f6
parent78e7783a237b8cfc3491aaad04bda5fe9568106e (diff)
downloadqt3d-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.cpp16
-rw-r--r--3rdparty/assimp/code/ObjFileMtlImporter.cpp26
-rwxr-xr-x[-rw-r--r--]3rdparty/assimp/code/ObjFileParser.cpp60
-rw-r--r--3rdparty/assimp/code/ObjTools.h49
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