// ------------------------------------------------------------------- // Set a new material definition as the current material. void ObjFileParser::getNewMaterial() { m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd); if( m_DataIt == m_DataItEnd ) { return; } char *pStart = &(*m_DataIt); std::string strMat( pStart, *m_DataIt ); while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *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() ) { // Show a warning, if material was not found DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat); m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; } else { // Set new material if ( needsNewMesh( strMat ) ) { createMesh(); } m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat ); } m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
// ------------------------------------------------------------------- // Copy the next word in a temporary buffer void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { size_t index = 0; m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd); while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { pBuffer[index] = *m_DataIt; index++; if( index == length - 1 ) { break; } ++m_DataIt; } ai_assert(index < length); pBuffer[index] = '\0'; }
// ------------------------------------------------------------------- // Stores values for a new object instance, name will be used to // identify it. void ObjFileParser::getObjectName() { m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); if( m_DataIt == m_DataItEnd ) { return; } char *pStart = &(*m_DataIt); while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { ++m_DataIt; } std::string strObjectName(pStart, &(*m_DataIt)); if (!strObjectName.empty()) { // Reset current object m_pModel->m_pCurrent = NULL; // Search for actual object for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin(); it != m_pModel->m_Objects.end(); ++it) { if ((*it)->m_strObjName == strObjectName) { m_pModel->m_pCurrent = *it; break; } } // Allocate a new object, if current one was not found before if( NULL == m_pModel->m_pCurrent ) { createObject( strObjectName ); } } m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
// ------------------------------------------------------------------------------------------------ void Tokenize(TokenList& output_tokens, const char* input) { ai_assert(input); // line and column numbers numbers are one-based unsigned int line = 1; unsigned int column = 1; bool comment = false; bool in_double_quotes = false; bool pending_data_token = false; const char* token_begin = NULL, *token_end = NULL; for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) { const char c = *cur; if (IsLineEnd(c)) { comment = false; column = 0; ++line; } if(comment) { continue; } if(in_double_quotes) { if (c == '\"') { in_double_quotes = false; token_end = cur; ProcessDataToken(output_tokens,token_begin,token_end,line,column); pending_data_token = false; } continue; } switch(c) { case '\"': if (token_begin) { TokenizeError("unexpected double-quote", line, column); } token_begin = cur; in_double_quotes = true; continue; case ';': ProcessDataToken(output_tokens,token_begin,token_end,line,column); comment = true; continue; case '{': ProcessDataToken(output_tokens,token_begin,token_end, line, column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column)); continue; case '}': ProcessDataToken(output_tokens,token_begin,token_end,line,column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column)); continue; case ',': if (pending_data_token) { ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true); } output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column)); continue; case ':': if (pending_data_token) { ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true); } else { TokenizeError("unexpected colon", line, column); } continue; } if (IsSpaceOrNewLine(c)) { if (token_begin) { // peek ahead and check if the next token is a colon in which // case this counts as KEY token. TokenType type = TokenType_DATA; for (const char* peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) { if (*peek == ':') { type = TokenType_KEY; cur = peek; break; } } ProcessDataToken(output_tokens,token_begin,token_end,line,column,type); } pending_data_token = false; } else { token_end = cur; if (!token_begin) { token_begin = cur; } pending_data_token = true; } } }
// ------------------------------------------------------------------- // Get values for a new face instance void ObjFileParser::getFace(aiPrimitiveType type) { copyNextLine(m_buffer, BUFFERSIZE); 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; std::vector<unsigned int> *pIndices = new std::vector<unsigned int>; std::vector<unsigned int> *pTexID = new std::vector<unsigned int>; std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>; bool hasNormal = false; const int vSize = m_pModel->m_Vertices.size(); const int vtSize = m_pModel->m_TextureCoord.size(); const int vnSize = m_pModel->m_Normals.size(); const bool vt = (!m_pModel->m_TextureCoord.empty()); const bool vn = (!m_pModel->m_Normals.empty()); int iStep = 0, iPos = 0; while (pPtr != pEnd) { iStep = 1; if (IsLineEnd(*pPtr)) break; if (*pPtr=='/' ) { if (type == aiPrimitiveType_POINT) { DefaultLogger::get()->error("Obj: Separator unexpected in point statement"); } if (iPos == 0) { //if there are no texture coordinates in the file, but normals if (!vt && vn) { iPos = 1; iStep++; } } iPos++; } else if( IsSpaceOrNewLine( *pPtr ) ) { iPos = 0; } else { //OBJ USES 1 Base ARRAYS!!!! const int iVal = atoi( pPtr ); // increment iStep position based off of the sign and # of digits int tmp = iVal; if (iVal < 0) ++iStep; while ( ( tmp = tmp / 10 )!=0 ) ++iStep; if ( iVal > 0 ) { // Store parsed index if ( 0 == iPos ) { pIndices->push_back( iVal-1 ); } else if ( 1 == iPos ) { pTexID->push_back( iVal-1 ); } else if ( 2 == iPos ) { pNormalID->push_back( iVal-1 ); hasNormal = true; } else { reportErrorTokenInFace(); } } else if ( iVal < 0 ) { // Store relatively index if ( 0 == iPos ) { pIndices->push_back( vSize + iVal ); } else if ( 1 == iPos ) { pTexID->push_back( vtSize + iVal ); } else if ( 2 == iPos ) { pNormalID->push_back( vnSize + iVal ); hasNormal = true; } else { reportErrorTokenInFace(); } } } pPtr += iStep; } if ( pIndices->empty() ) { DefaultLogger::get()->error("Obj: Ignoring empty face"); m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); delete pTexID; return; } ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type ); // Set active material, if one set if (NULL != m_pModel->m_pCurrentMaterial) face->m_pMaterial = m_pModel->m_pCurrentMaterial; else face->m_pMaterial = m_pModel->m_pDefaultMaterial; // Create a default object, if nothing is there if ( NULL == m_pModel->m_pCurrent ) createObject( "defaultobject" ); // Assign face to mesh if ( NULL == m_pModel->m_pCurrentMesh ) { createMesh(); } // Store the face m_pModel->m_pCurrentMesh->m_Faces.push_back( face ); m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size(); m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size(); if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) { m_pModel->m_pCurrentMesh->m_hasNormals = true; } // Skip the rest of the line m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }