Merge pull request #770 from assimp/revert-765-master

Revert "Fix issue: OBJ import takes forever (#759)"
pull/772/head
Kim Kulling 2016-01-26 00:14:27 +01:00
commit 11d0085f4d
4 changed files with 245 additions and 176 deletions

View File

@ -145,6 +145,38 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
modelName = pFile; modelName = pFile;
} }
// This next stage takes ~ 1/3th of the total readFile task
// so should amount for 1/3th of the progress
// only update every 100KB or it'll be too slow
unsigned int progress = 0;
unsigned int progressCounter = 0;
const unsigned int updateProgressEveryBytes = 100 * 1024;
const unsigned int progressTotal = (3*m_Buffer.size()/updateProgressEveryBytes);
// process all '\'
std::vector<char> ::iterator iter = m_Buffer.begin();
while (iter != m_Buffer.end())
{
if (*iter == '\\')
{
// remove '\'
iter = m_Buffer.erase(iter);
// remove next character
while (*iter == '\r' || *iter == '\n')
iter = m_Buffer.erase(iter);
}
else
++iter;
if (++progressCounter >= updateProgressEveryBytes)
{
m_progress->UpdateFileRead(++progress, progressTotal);
progressCounter = 0;
}
}
// 1/3rd progress
m_progress->UpdateFileRead(1, 3);
// parse the file into a temporary representation // parse the file into a temporary representation
ObjFileParser parser(m_Buffer, modelName, pIOHandler, m_progress); ObjFileParser parser(m_Buffer, modelName, pIOHandler, m_progress);

View File

@ -61,13 +61,16 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Constructor with loaded data and directories. // Constructor with loaded data and directories.
ObjFileParser::ObjFileParser(const std::vector<char> &data,const std::string &modelName, IOSystem *io, ProgressHandler* progress ) : ObjFileParser::ObjFileParser(std::vector<char> &data,const std::string &modelName, IOSystem *io, ProgressHandler* progress ) :
m_DataBuffer(data), m_DataIt(data.begin()),
m_DataItEnd(data.end()),
m_pModel(NULL), m_pModel(NULL),
m_uiLine(0), m_uiLine(0),
m_pIO( io ), m_pIO( io ),
m_progress(progress) m_progress(progress)
{ {
std::fill_n(m_buffer,Buffersize,0);
// Create the model instance to store all the data // Create the model instance to store all the data
m_pModel = new ObjFile::Model(); m_pModel = new ObjFile::Model();
m_pModel->m_ModelName = modelName; m_pModel->m_ModelName = modelName;
@ -101,77 +104,48 @@ ObjFile::Model *ObjFileParser::GetModel() const
// File parsing method. // File parsing method.
void ObjFileParser::parseFile() void ObjFileParser::parseFile()
{ {
//! Iterator to current position in buffer if (m_DataIt == m_DataItEnd)
ConstDataArrayIt dataIt = m_DataBuffer.begin();
//! Iterator to end position of buffer
const ConstDataArrayIt dataItEnd = m_DataBuffer.end();
if (dataIt == dataItEnd)
return; return;
//! Helper buffer
std::vector<char> helperBuffer;
// only update every 100KB or it'll be too slow // only update every 100KB or it'll be too slow
const unsigned int updateProgressEveryBytes = 100 * 1024; const unsigned int updateProgressEveryBytes = 100 * 1024;
unsigned int progressCounter = 0; unsigned int progressCounter = 0;
const unsigned int bytesToProcess = std::distance(dataIt, dataItEnd); const unsigned int bytesToProcess = std::distance(m_DataIt, m_DataItEnd);
const unsigned int progressTotal = bytesToProcess; const unsigned int progressTotal = 3 * bytesToProcess;
const unsigned int progressOffset = bytesToProcess;
unsigned int processed = 0; unsigned int processed = 0;
ConstDataArrayIt lastDataIt = dataIt; DataArrayIt lastDataIt = m_DataIt;
while (dataIt != dataItEnd) while (m_DataIt != m_DataItEnd)
{ {
// Handle progress reporting // Handle progress reporting
processed += std::distance(lastDataIt, dataIt); processed += std::distance(lastDataIt, m_DataIt);
lastDataIt = dataIt; lastDataIt = m_DataIt;
if (processed > (progressCounter * updateProgressEveryBytes)) if (processed > (progressCounter * updateProgressEveryBytes))
{ {
progressCounter++; progressCounter++;
m_progress->UpdateFileRead(processed, progressTotal); m_progress->UpdateFileRead(progressOffset + processed*2, progressTotal);
} }
// take the next line and copy it into a helper buffer
// all subsequant parsing should use the helper buffer
copyNextLine(helperBuffer, dataIt, dataItEnd);
if (helperBuffer[0] == '\0')
{
// either empty line, or end of file
if (dataIt == dataItEnd)
{
// end of file
return;
}
// else empty line, so skip
continue;
}
//! Iterator to current position in helper buffer
ConstDataArrayIt helperIt = helperBuffer.begin();
//! Iterator to end of helper buffer
const ConstDataArrayIt helperItEnd = helperBuffer.end();
// parse line // parse line
switch (*helperIt) switch (*m_DataIt)
{ {
case 'v': // Parse a vertex texture coordinate case 'v': // Parse a vertex texture coordinate
{ {
if (++helperIt != helperItEnd) { ++m_DataIt;
if (*helperIt == ' ' || *helperIt == '\t') { if (*m_DataIt == ' ' || *m_DataIt == '\t') {
// read in vertex definition // read in vertex definition
getVector3(m_pModel->m_Vertices, ++helperIt, helperItEnd); getVector3(m_pModel->m_Vertices);
} else if (*helperIt == 't') { } else if (*m_DataIt == 't') {
// read in texture coordinate ( 2D or 3D ) // read in texture coordinate ( 2D or 3D )
getVector( m_pModel->m_TextureCoord, ++helperIt, helperItEnd); ++m_DataIt;
} else if (*helperIt == 'n') { getVector( m_pModel->m_TextureCoord );
// Read in normal vector definition } else if (*m_DataIt == 'n') {
getVector3( m_pModel->m_Normals, ++helperIt, helperItEnd); // Read in normal vector definition
} ++m_DataIt;
// else unknown line getVector3( m_pModel->m_Normals );
} }
// else no more data
} }
break; break;
@ -179,36 +153,35 @@ void ObjFileParser::parseFile()
case 'l': case 'l':
case 'f': case 'f':
{ {
getFace(*helperIt == 'f' ? aiPrimitiveType_POLYGON : (*helperIt == 'l' getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l'
? aiPrimitiveType_LINE : aiPrimitiveType_POINT), ++helperIt, helperItEnd); ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
} }
break; break;
case '#': // Parse a comment case '#': // Parse a comment
{ {
// just ignore it getComment();
} }
break; break;
case 'u': // Parse a material desc. setter case 'u': // Parse a material desc. setter
{ {
getMaterialDesc(++helperIt, helperItEnd); getMaterialDesc();
} }
break; break;
case 'm': // Parse a material library or merging group ('mg') case 'm': // Parse a material library or merging group ('mg')
{ {
if (*(helperIt + 1) == 'g') if (*(m_DataIt + 1) == 'g')
getGroupNumberAndResolution(); getGroupNumberAndResolution();
else { else
getMaterialLib(++helperIt, helperItEnd); getMaterialLib();
}
} }
break; break;
case 'g': // Parse group name case 'g': // Parse group name
{ {
getGroupName(++helperIt, helperItEnd); getGroupName();
} }
break; break;
@ -220,12 +193,13 @@ void ObjFileParser::parseFile()
case 'o': // Parse object name case 'o': // Parse object name
{ {
getObjectName(++helperIt, helperItEnd); getObjectName();
} }
break; break;
default: default:
{ {
// unknown line, skip m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
break; break;
} }
@ -234,37 +208,34 @@ void ObjFileParser::parseFile()
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Copy the next word in a temporary buffer // Copy the next word in a temporary buffer
bool ObjFileParser::getNextFloat(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd, float &result) void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
{ {
std::vector<char> tmpBuffer; size_t index = 0;
dataIt = getNextWord<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
while( dataIt != dataItEnd && !IsSpaceOrNewLine( *dataIt ) ) { while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
tmpBuffer.push_back(*dataIt); pBuffer[index] = *m_DataIt;
++dataIt; index++;
if( index == length - 1 ) {
break;
}
++m_DataIt;
} }
if (tmpBuffer.size() == 0) ai_assert(index < length);
{ pBuffer[index] = '\0';
return false;
}
tmpBuffer.push_back('\0');
result = fast_atof(&tmpBuffer[0]);
return true;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Copy the next line into a temporary buffer // Copy the next line into a temporary buffer
void ObjFileParser::copyNextLine(std::vector<char> &buffer, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
{ {
// clear old data out. This is O(1) since a char is a "trivially-destructable type" size_t index = 0u;
buffer.clear();
// some OBJ files have line continuations using \ (such as in C++ et al) // some OBJ files have line continuations using \ (such as in C++ et al)
bool continuation = false; bool continuation = false;
for (;dataIt != dataItEnd; ++dataIt) for (;m_DataIt != m_DataItEnd && index < length-1; ++m_DataIt)
{ {
const char c = *dataIt; const char c = *m_DataIt;
if (c == '\\') { if (c == '\\') {
continuation = true; continuation = true;
continue; continue;
@ -272,84 +243,98 @@ void ObjFileParser::copyNextLine(std::vector<char> &buffer, ConstDataArrayIt &da
if (c == '\n' || c == '\r') { if (c == '\n' || c == '\r') {
if(continuation) { if(continuation) {
buffer.push_back(' '); pBuffer[ index++ ] = ' ';
continue; continue;
} }
// end of line, update dataIt to point to the start of the next
dataIt = skipLine<ConstDataArrayIt>(dataIt, dataItEnd, m_uiLine );
break; break;
} }
continuation = false; continuation = false;
buffer.push_back(c); pBuffer[ index++ ] = c;
} }
// add a NULL terminator ai_assert(index < length);
buffer.push_back('\0'); pBuffer[ index ] = '\0';
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) { void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
size_t numComponents( 0 ); size_t numComponents( 0 );
float components[3]; const char* tmp( &m_DataIt[0] );
while( dataIt != dataItEnd ) { while( !IsLineEnd( *tmp ) ) {
if (!getNextFloat(dataIt, dataItEnd, components[numComponents])) if ( !SkipSpaces( &tmp ) ) {
{
// failed
break;
}
numComponents++;
if (numComponents == 3)
{
// 3 is the max
break; break;
} }
SkipToken( tmp );
++numComponents;
} }
float x, y, z;
if( 2 == numComponents ) { if( 2 == numComponents ) {
components[2] = 0.0f; copyNextWord( m_buffer, Buffersize );
} else if( 3 != numComponents ) { x = ( float ) fast_atof( m_buffer );
copyNextWord( m_buffer, Buffersize );
y = ( float ) fast_atof( m_buffer );
z = 0.0;
} else if( 3 == numComponents ) {
copyNextWord( m_buffer, Buffersize );
x = ( float ) fast_atof( m_buffer );
copyNextWord( m_buffer, Buffersize );
y = ( float ) fast_atof( m_buffer );
copyNextWord( m_buffer, Buffersize );
z = ( float ) fast_atof( m_buffer );
} else {
throw DeadlyImportError( "OBJ: Invalid number of components" ); throw DeadlyImportError( "OBJ: Invalid number of components" );
} }
point3d_array.push_back( aiVector3D( components[0], components[1], components[2] ) ); point3d_array.push_back( aiVector3D( x, y, z ) );
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get values for a new 3D vector instance // Get values for a new 3D vector instance
void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) { void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
float x, y, z; float x, y, z;
if (!getNextFloat(dataIt, dataItEnd, x) || copyNextWord(m_buffer, Buffersize);
!getNextFloat(dataIt, dataItEnd, y) || x = (float) fast_atof(m_buffer);
!getNextFloat(dataIt, dataItEnd, z))
{ copyNextWord(m_buffer, Buffersize);
throw DeadlyImportError( "OBJ: Invalid number of components" ); y = (float) fast_atof(m_buffer);
}
else copyNextWord( m_buffer, Buffersize );
{ z = ( float ) fast_atof( m_buffer );
point3d_array.push_back( aiVector3D( x, y, z ) );
} point3d_array.push_back( aiVector3D( x, y, z ) );
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get values for a new 2D vector instance // Get values for a new 2D vector instance
void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) { void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
float x, y; float x, y;
if (!getNextFloat(dataIt, dataItEnd, x) || copyNextWord(m_buffer, Buffersize);
!getNextFloat(dataIt, dataItEnd, y)) x = (float) fast_atof(m_buffer);
{
throw DeadlyImportError( "OBJ: Invalid number of components" ); copyNextWord(m_buffer, Buffersize);
} y = (float) fast_atof(m_buffer);
else
{ point2d_array.push_back(aiVector2D(x, y));
point2d_array.push_back( aiVector2D( x, y ) );
} m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get values for a new face instance // Get values for a new face instance
void ObjFileParser::getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getFace(aiPrimitiveType type)
{ {
ConstDataArrayIt pPtr = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); copyNextLine(m_buffer, Buffersize);
if (pPtr == dataItEnd || *pPtr == '\0') if (m_DataIt == m_DataItEnd)
return;
char *pPtr = m_buffer;
char *pEnd = &pPtr[Buffersize];
pPtr = getNextToken<char*>(pPtr, pEnd);
if (pPtr == pEnd || *pPtr == '\0')
return; return;
std::vector<unsigned int> *pIndices = new std::vector<unsigned int>; std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
@ -364,7 +349,7 @@ void ObjFileParser::getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, cons
const bool vt = (!m_pModel->m_TextureCoord.empty()); const bool vt = (!m_pModel->m_TextureCoord.empty());
const bool vn = (!m_pModel->m_Normals.empty()); const bool vn = (!m_pModel->m_Normals.empty());
int iStep = 0, iPos = 0; int iStep = 0, iPos = 0;
while (pPtr != dataItEnd) while (pPtr != pEnd)
{ {
iStep = 1; iStep = 1;
@ -393,7 +378,7 @@ void ObjFileParser::getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, cons
else else
{ {
//OBJ USES 1 Base ARRAYS!!!! //OBJ USES 1 Base ARRAYS!!!!
const int iVal = atoi( &pPtr[0] ); const int iVal = atoi( pPtr );
// increment iStep position based off of the sign and # of digits // increment iStep position based off of the sign and # of digits
int tmp = iVal; int tmp = iVal;
@ -450,8 +435,8 @@ void ObjFileParser::getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, cons
if ( pIndices->empty() ) { if ( pIndices->empty() ) {
DefaultLogger::get()->error("Obj: Ignoring empty face"); DefaultLogger::get()->error("Obj: Ignoring empty face");
// skip line and clean up
// clean up m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
delete pNormalID; delete pNormalID;
delete pTexID; delete pTexID;
delete pIndices; delete pIndices;
@ -485,25 +470,31 @@ void ObjFileParser::getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, cons
if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) { if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) {
m_pModel->m_pCurrentMesh->m_hasNormals = true; m_pModel->m_pCurrentMesh->m_hasNormals = true;
} }
// Skip the rest of the line
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get values for a new material description // Get values for a new material description
void ObjFileParser::getMaterialDesc(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getMaterialDesc()
{ {
// Get next data for material data // Get next data for material data
dataIt = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
if (dataIt == dataItEnd) { if (m_DataIt == m_DataItEnd) {
return; return;
} }
char *pStart = &(*m_DataIt);
while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
++m_DataIt;
}
// In some cases we should ignore this 'usemtl' command, this variable helps us to do so // In some cases we should ignore this 'usemtl' command, this variable helps us to do so
bool skip = false; bool skip = false;
// Get name // Get name
std::string strName(dataIt, dataItEnd); std::string strName(pStart, &(*m_DataIt));
strName = trim_whitespaces(strName); strName = trim_whitespaces(strName);
if (strName.empty()) if (strName.empty())
skip = true; skip = true;
@ -534,20 +525,46 @@ void ObjFileParser::getMaterialDesc(ConstDataArrayIt &dataIt, const ConstDataArr
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
} }
// Skip rest of line
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
// -------------------------------------------------------------------
// Get a comment, values will be skipped
void ObjFileParser::getComment()
{
while (m_DataIt != m_DataItEnd)
{
if ( '\n' == (*m_DataIt))
{
++m_DataIt;
break;
}
else
{
++m_DataIt;
}
}
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get material library from file. // Get material library from file.
void ObjFileParser::getMaterialLib(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getMaterialLib()
{ {
// Translate tuple // Translate tuple
dataIt = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
if( dataIt == dataItEnd ) { if( m_DataIt == m_DataItEnd ) {
return; return;
} }
char *pStart = &(*m_DataIt);
while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
++m_DataIt;
}
// Check for existence // Check for existence
const std::string strMatName(dataIt, dataItEnd); const std::string strMatName(pStart, &(*m_DataIt));
std::string absName; std::string absName;
if ( m_pIO->StackSize() > 0 ) { if ( m_pIO->StackSize() > 0 ) {
std::string path = m_pIO->CurrentDirectory(); std::string path = m_pIO->CurrentDirectory();
@ -562,6 +579,7 @@ void ObjFileParser::getMaterialLib(ConstDataArrayIt &dataIt, const ConstDataArra
if (!pFile ) { if (!pFile ) {
DefaultLogger::get()->error( "OBJ: Unable to locate material file " + strMatName ); DefaultLogger::get()->error( "OBJ: Unable to locate material file " + strMatName );
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
return; return;
} }
@ -579,19 +597,19 @@ void ObjFileParser::getMaterialLib(ConstDataArrayIt &dataIt, const ConstDataArra
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Set a new material definition as the current material. // Set a new material definition as the current material.
void ObjFileParser::getNewMaterial(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getNewMaterial()
{ {
dataIt = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
dataIt = getNextWord<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
if( dataIt == dataItEnd ) { if( m_DataIt == m_DataItEnd ) {
return; return;
} }
const char *pStart = &(*dataIt); char *pStart = &(*m_DataIt);
while( dataIt != dataItEnd && IsSpaceOrNewLine( *dataIt ) ) { std::string strMat( pStart, *m_DataIt );
++dataIt; while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *m_DataIt ) ) {
++m_DataIt;
} }
std::string strMat( pStart, *dataIt );
std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat ); std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
if ( it == m_pModel->m_MaterialMap.end() ) if ( it == m_pModel->m_MaterialMap.end() )
{ {
@ -608,6 +626,8 @@ void ObjFileParser::getNewMaterial(ConstDataArrayIt &dataIt, const ConstDataArra
} }
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat ); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
} }
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -630,13 +650,12 @@ int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Getter for a group name. // Getter for a group name.
void ObjFileParser::getGroupName(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getGroupName()
{ {
std::string strGroupName; std::string strGroupName;
dataIt = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
dataIt = getName<ConstDataArrayIt>(dataIt, dataItEnd, strGroupName); if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
if( isEndOfBuffer( dataIt, dataItEnd ) ) {
return; return;
} }
@ -662,6 +681,7 @@ void ObjFileParser::getGroupName(ConstDataArrayIt &dataIt, const ConstDataArrayI
} }
m_pModel->m_strActiveGroup = strGroupName; m_pModel->m_strActiveGroup = strGroupName;
} }
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -669,6 +689,8 @@ void ObjFileParser::getGroupName(ConstDataArrayIt &dataIt, const ConstDataArrayI
void ObjFileParser::getGroupNumber() void ObjFileParser::getGroupNumber()
{ {
// Not used // Not used
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -676,19 +698,25 @@ void ObjFileParser::getGroupNumber()
void ObjFileParser::getGroupNumberAndResolution() void ObjFileParser::getGroupNumberAndResolution()
{ {
// Not used // Not used
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Stores values for a new object instance, name will be used to // Stores values for a new object instance, name will be used to
// identify it. // identify it.
void ObjFileParser::getObjectName(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd) void ObjFileParser::getObjectName()
{ {
dataIt = getNextToken<ConstDataArrayIt>(dataIt, dataItEnd); m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
if( dataIt == dataItEnd ) { if( m_DataIt == m_DataItEnd ) {
return; return;
} }
char *pStart = &(*m_DataIt);
while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
++m_DataIt;
}
std::string strObjectName(dataIt, dataItEnd); std::string strObjectName(pStart, &(*m_DataIt));
if (!strObjectName.empty()) if (!strObjectName.empty())
{ {
// Reset current object // Reset current object
@ -711,6 +739,7 @@ void ObjFileParser::getObjectName(ConstDataArrayIt &dataIt, const ConstDataArray
createObject( strObjectName ); createObject( strObjectName );
} }
} }
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Creates a new object instance // Creates a new object instance
@ -774,6 +803,7 @@ bool ObjFileParser::needsNewMesh( const std::string &rMaterialName )
// Shows an error in parsing process. // Shows an error in parsing process.
void ObjFileParser::reportErrorTokenInFace() void ObjFileParser::reportErrorTokenInFace()
{ {
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
DefaultLogger::get()->error("OBJ: Not supported token in face description detected"); DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
} }

View File

@ -65,13 +65,14 @@ class ProgressHandler;
/// \brief Parser for a obj waveform file /// \brief Parser for a obj waveform file
class ObjFileParser { class ObjFileParser {
public: public:
static const size_t Buffersize = 4096;
typedef std::vector<char> DataArray; typedef std::vector<char> DataArray;
typedef std::vector<char>::iterator DataArrayIt; typedef std::vector<char>::iterator DataArrayIt;
typedef std::vector<char>::const_iterator ConstDataArrayIt; typedef std::vector<char>::const_iterator ConstDataArrayIt;
public: public:
/// \brief Constructor with data array. /// \brief Constructor with data array.
ObjFileParser(const std::vector<char> &Data,const std::string &strModelName, IOSystem* io, ProgressHandler* progress); ObjFileParser(std::vector<char> &Data,const std::string &strModelName, IOSystem* io, ProgressHandler* progress);
/// \brief Destructor /// \brief Destructor
~ObjFileParser(); ~ObjFileParser();
/// \brief Model getter. /// \brief Model getter.
@ -81,25 +82,27 @@ private:
/// Parse the loaded file /// Parse the loaded file
void parseFile(); void parseFile();
/// Method to copy the new delimited word in the current line. /// Method to copy the new delimited word in the current line.
bool getNextFloat(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd, float &result); void copyNextWord(char *pBuffer, size_t length);
/// Method to copy the new line. /// Method to copy the new line.
void copyNextLine(std::vector<char> &buffer, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void copyNextLine(char *pBuffer, size_t length);
/// Stores the vector /// Stores the vector
void getVector( std::vector<aiVector3D> &point3d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getVector( std::vector<aiVector3D> &point3d_array );
/// Stores the following 3d vector. /// Stores the following 3d vector.
void getVector3(std::vector<aiVector3D> &point3d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getVector3( std::vector<aiVector3D> &point3d_array );
/// Stores the following 3d vector. /// Stores the following 3d vector.
void getVector2(std::vector<aiVector2D> &point2d_array, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getVector2(std::vector<aiVector2D> &point2d_array);
/// Stores the following face. /// Stores the following face.
void getFace(aiPrimitiveType type, ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getFace(aiPrimitiveType type);
/// Reads the material description. /// Reads the material description.
void getMaterialDesc(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getMaterialDesc();
/// Gets a comment.
void getComment();
/// Gets a a material library. /// Gets a a material library.
void getMaterialLib(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getMaterialLib();
/// Creates a new material. /// Creates a new material.
void getNewMaterial(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getNewMaterial();
/// Gets the group name from file. /// Gets the group name from file.
void getGroupName(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getGroupName();
/// Gets the group number from file. /// Gets the group number from file.
void getGroupNumber(); void getGroupNumber();
/// Gets the group number and resolution from file. /// Gets the group number and resolution from file.
@ -107,7 +110,7 @@ private:
/// Returns the index of the material. Is -1 if not material was found. /// Returns the index of the material. Is -1 if not material was found.
int getMaterialIndex( const std::string &strMaterialName ); int getMaterialIndex( const std::string &strMaterialName );
/// Parse object name /// Parse object name
void getObjectName(ConstDataArrayIt &dataIt, const ConstDataArrayIt dataItEnd); void getObjectName();
/// Creates a new object. /// Creates a new object.
void createObject( const std::string &strObjectName ); void createObject( const std::string &strObjectName );
/// Creates a new mesh. /// Creates a new mesh.
@ -125,12 +128,16 @@ private:
/// Default material name /// Default material name
static const std::string DEFAULT_MATERIAL; static const std::string DEFAULT_MATERIAL;
//! Data buffer //! Iterator to current position in buffer
const std::vector<char> &m_DataBuffer; DataArrayIt m_DataIt;
//! Iterator to end position of buffer
DataArrayIt m_DataItEnd;
//! Pointer to model instance //! Pointer to model instance
ObjFile::Model *m_pModel; ObjFile::Model *m_pModel;
//! Current line (for debugging) //! Current line (for debugging)
unsigned int m_uiLine; unsigned int m_uiLine;
//! Helper buffer
char m_buffer[Buffersize];
/// Pointer to IO system instance. /// Pointer to IO system instance.
IOSystem *m_pIO; IOSystem *m_pIO;
//! Pointer to progress handler //! Pointer to progress handler

View File

@ -141,7 +141,7 @@ inline char_t getName( char_t it, char_t end, std::string &name )
return end; return end;
} }
char_t pStart = it; char *pStart = &( *it );
while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) { while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
++it; ++it;
} }
@ -153,10 +153,10 @@ inline char_t getName( char_t it, char_t end, std::string &name )
// Get name // Get name
// if there is no name, and the previous char is a separator, come back to start // if there is no name, and the previous char is a separator, come back to start
while (it < pStart) { while (&(*it) < pStart) {
++it; ++it;
} }
std::string strName( pStart, it ); std::string strName( pStart, &(*it) );
if ( strName.empty() ) if ( strName.empty() )
return it; return it;
else else