// -------------------------------------------------------------------
//  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 );
}
예제 #4
0
// ------------------------------------------------------------------------------------------------
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 );
}