// ------------------------------------------------------------------- // Get material library from file. void ObjFileParser::getMaterialLib() { // Translate tuple m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); if( m_DataIt == m_DataItEnd ) { return; } char *pStart = &(*m_DataIt); while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) { ++m_DataIt; } // Check for existence const std::string strMatName(pStart, &(*m_DataIt)); IOStream *pFile = m_pIO->Open(strMatName); if (!pFile ) { DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName); m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); return; } // Import material library data from file std::vector<char> buffer; BaseImporter::TextFileToBuffer(pFile,buffer); m_pIO->Close( pFile ); // Importing the material library ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel ); }
// ------------------------------------------------------------------- void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) { size_t numComponents( 0 ); DataArrayIt tmp( m_DataIt ); while( !IsLineEnd( *tmp ) ) { if( *tmp == ' ' ) { ++numComponents; } tmp++; } float x, y, z; if( 2 == numComponents ) { copyNextWord( m_buffer, BUFFERSIZE ); 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 { ai_assert( !"Invalid number of components" ); } point3d_array.push_back( aiVector3D( x, y, z ) ); m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
// ------------------------------------------------------------------- // Creates a material from loaded data. void ObjFileMtlImporter::createMaterial() { std::string line( "" ); while( !IsLineEnd( *m_DataIt ) ) { line += *m_DataIt; ++m_DataIt; } std::vector<std::string> token; const unsigned int numToken = tokenize<std::string>( line, token, " \t" ); std::string name( "" ); if ( numToken == 1 ) { name = AI_DEFAULT_MATERIAL_NAME; } else { // skip newmtl and all following white spaces std::size_t first_ws_pos = line.find_first_of(" \t"); std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos); if (first_non_ws_pos != std::string::npos) { name = line.substr(first_non_ws_pos); } } 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( name ); m_pModel->m_MaterialLib.push_back( name ); m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial; } else { // Use older material m_pModel->m_pCurrentMaterial = (*it).second; } }
// ------------------------------------------------------------------- void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); while( !IsLineEnd( *tmp ) ) { if ( !SkipSpaces( &tmp ) ) { break; } SkipToken( tmp ); ++numComponents; } float x, y, z; if( 2 == numComponents ) { copyNextWord( m_buffer, BUFFERSIZE ); 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" ); } point3d_array.push_back( aiVector3D( x, y, z ) ); m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
// ------------------------------------------------------------------- // Get values for a new material description void ObjFileParser::getMaterialDesc() { // 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( 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 bool skip = false; // Get name std::string strName(pStart, &(*m_DataIt)); strName = trim_whitespaces(strName); if (strName.empty()) skip = true; // If the current mesh has the same material, we simply ignore that 'usemtl' command // There is no need to create another object or even mesh here if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName)) skip = true; if (!skip) { // Search for material std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find(strName); if (it == m_pModel->m_MaterialMap.end()) { // Not found, use default material m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str(); } else { // Found, using detected material m_pModel->m_pCurrentMaterial = (*it).second; } if (needsNewMesh(strName)) createMesh(strName); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName); } // Skip rest of line m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
size_t ObjFileParser::getNumComponentsInLine() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); while( !IsLineEnd( *tmp ) ) { if ( !SkipSpaces( &tmp ) ) { break; } SkipToken( tmp ); ++numComponents; } return numComponents; }
// ------------------------------------------------------------------- // Get material library from file. void ObjFileParser::getMaterialLib() { // Translate tuple m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd); if( m_DataIt == m_DataItEnd ) { return; } char *pStart = &(*m_DataIt); while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) { ++m_DataIt; } // Check for existence const std::string strMatName(pStart, &(*m_DataIt)); std::string absName; if ( m_pIO->StackSize() > 0 ) { std::string path = m_pIO->CurrentDirectory(); if ( '/' != *path.rbegin() ) { path += '/'; } absName = path + strMatName; } else { absName = strMatName; } IOStream *pFile = m_pIO->Open( absName ); if (!pFile ) { DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName); std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl"; DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName); pFile = m_pIO->Open(strMatFallbackName); if (!pFile) { DefaultLogger::get()->error("OBJ: Unable to locate fallback material file " + strMatName); m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine); return; } } // Import material library data from file. // Some exporters (e.g. Silo) will happily write out empty // material files if the model doesn't use any materials, so we // allow that. std::vector<char> buffer; BaseImporter::TextFileToBuffer( pFile, buffer, BaseImporter::ALLOW_EMPTY ); m_pIO->Close( pFile ); // Importing the material library ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel ); }
// ------------------------------------------------------------------- // 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( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) { ++m_DataIt; } // Get name std::string strName(pStart, &(*m_DataIt)); if ( strName.empty()) return; // Search for material std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName ); if ( it == m_pModel->m_MaterialMap.end() ) { // Not found, use default material m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); } else { // Found, using detected material m_pModel->m_pCurrentMaterial = (*it).second; if ( needsNewMesh( strName )) { createMesh(); } m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName ); } // Skip rest of line m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine ); }
// ------------------------------------------------------------------- // Loads a color definition void ObjFileMtlImporter::getColorRGBA( aiColor3D *pColor ) { ai_assert( NULL != pColor ); float r( 0.0f ), g( 0.0f ), b( 0.0f ); m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, r ); pColor->r = r; // we have to check if color is default 0 with only one token if( !IsLineEnd( *m_DataIt ) ) { m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, g ); m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, b ); } pColor->g = g; pColor->b = b; }
// ------------------------------------------------------------------------------------------------ // Remove line comments from a file void CommentRemover::RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement /* = ' ' */) { // validate parameters ai_assert(NULL != szComment && NULL != szBuffer && *szComment); const size_t len = strlen(szComment); while (*szBuffer) { // skip over quotes if (*szBuffer == '\"' || *szBuffer == '\'') while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); if (!strncmp(szBuffer,szComment,len)) { while (!IsLineEnd(*szBuffer)) *szBuffer++ = chReplacement; } ++szBuffer; } }
// ------------------------------------------------------------------- // 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 ( isSeparator(*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 ); 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 ); }
// ------------------------------------------------------------------------------------------------ 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; } } }
int ReadInLine(FILE* pFile, REC_INFO* pLineInfo) { char* pLine = NULL; int ret = 0; unsigned int readPos = 0; unsigned int eleLen = 0; size_t lineLen = 0; REC_INFO* pEleEnd = pLineInfo; enum ELE_SEPERATOR_TYPE sepType = SEP_END; pLine = (char*)malloc(MAX_LINE_CHAR_COUNT); OutString(DBG_RES, "Malloc Local pLine\n"); if(pLine == NULL) { return -1; } memset(pLine, 0, MAX_LINE_CHAR_COUNT); ret = -2; while(fgets(pLine, MAX_LINE_CHAR_COUNT, pFile) != NULL) { lineLen = strlen(pLine); for(readPos = 0, eleLen = 0; readPos < lineLen; ++readPos) { if(IsSeperator(pLine[readPos],&sepType)) { if(eleLen > 0) { pEleEnd = PushEleEnd(pEleEnd, ELE_TEXT, pLine + readPos - eleLen, eleLen); if(pEleEnd == NULL) { ret = -3; goto FREE_AND_RETURN; } eleLen = 0; } pEleEnd = PushEleEnd(pEleEnd, ELE_SEPERATOR, &sepType, 0); if(pEleEnd == NULL) { ret = -3; goto FREE_AND_RETURN; } } else { ++eleLen; } } if(eleLen != 0) { pEleEnd = PushEleEnd(pEleEnd, ELE_TEXT, pLine + readPos - eleLen, eleLen); if(pEleEnd == NULL) { ret = -3; goto FREE_AND_RETURN; } eleLen = 0; } if(lineLen == 0) { ret = -4; goto FREE_AND_RETURN; } if(IsLineEnd(pLine[lineLen - 1])) { ret = 0; goto FREE_AND_RETURN; } } FREE_AND_RETURN: free(pLine); OutString(DBG_RES, "FREE Local pLine\n"); return ret; }
void Font::SplitTextToStrings(const WideString & text, const Vector2 & targetRectSize, Vector<WideString> & resultVector) { int32 targetWidth = (int32)(targetRectSize.dx * Core::GetVirtualToPhysicalFactor()); enum { SKIP = 0, GOODCHAR, // all characters we like (symbols, special chars, except \n and space FINISH, // process last line EXIT, }; // Yuri Coder, 2013/12/10. Replace "\n" occurrences (two chars) to '\n' (one char) is done by Yaml parser, // so appropriate code (state NEXTLINE)is removed from here. See please MOBWOT-6499. SeparatorPositions separator; resultVector.clear(); int state = SKIP; int totalSize = (int)text.length(); Vector<float32> sizes; GetStringSize(text, &sizes); if(sizes.size() == 0) { return; } bool wasSeparator = false; for(int pos = 0; state != EXIT; pos++) { char16 t = 0; if(pos < totalSize) { t = text[pos]; } bool isSeparator = IsWordSeparator(t); switch (state) { case SKIP: if (t == 0){ state = FINISH; break; } // if end of string process FINISH state and exit else if (IsSpace(t))break; // if space continue with the same state else if(IsLineEnd(t)) { // this block is copied from case NEXTLINE: if(t == 'n') // unlike in NEXTLINE where we ignore 2 symbols, here we ignore only one // so last position is pos instead of (pos-1) if (separator.IsLineInitialized()) // if we already have something in current line we add to result { AddCurrentLine(text, pos, separator, resultVector); }else { resultVector.push_back(L""); // here we add empty line if there was no characters in current line } state = SKIP; //always switch to SKIP because we do not know here what will be next break; } else // everything else is good characters { state = GOODCHAR; separator.lastWordStart = pos; separator.lastWordEnd = pos; if (!separator.IsLineInitialized()) separator.currentLineStart = pos; } break; case GOODCHAR: { if(IsSpace(t) || IsLineEnd(t) || t == 0 || (wasSeparator && !isSeparator)) // if we've found any possible separator process current line { //calculate current line width float32 currentLineWidth = 0; int32 startPos = (separator.IsLineInitialized()) ? separator.currentLineStart : 0; for (int i = startPos; i < pos ; i++) { currentLineWidth += sizes[i]; } if((currentLineWidth < targetWidth) || ((IsSpace(t) || isSeparator) && 0 == targetWidth)) { // pos could be the end of line. We need to save it if(IsLineEnd(t) || t == 0) { AddCurrentLine(text, pos, separator, resultVector); } else { separator.currentLineEnd = pos; separator.lastWordEnd = pos; } } else if(currentLineWidth == targetWidth) { // line fit all available space DVASSERT(pos > separator.currentLineStart); AddCurrentLine(text, pos, separator, resultVector); } else { //currentLineWidth > targetWidth int32 currentLineLength = separator.currentLineEnd - separator.currentLineStart; if((currentLineLength > 0)) { // use previous position of separator to split text pos = separator.currentLineEnd; AddCurrentLine(text, pos, separator, resultVector); t = 0; if(pos + 1 < totalSize) { t = text[pos + 1]; } if(IsSpace(t) || IsLineEnd(t) || t == 0) { state = SKIP; } else { state = GOODCHAR; separator.lastWordStart = pos; separator.lastWordEnd = pos; if (!separator.IsLineInitialized()) separator.currentLineStart = pos; } break; } else if(pos) { // truncate text by symbol for very long word if(0 == targetWidth) { AddCurrentLine(text, pos, separator, resultVector); } else { int32 endPos = (separator.IsLineInitialized()) ? separator.currentLineStart : 0; for (int i = pos-1; i >= endPos; --i) { currentLineWidth -= sizes[i]; if(currentLineWidth <= targetWidth) { separator.currentLineEnd = i; int32 currentLineLength = separator.currentLineEnd - separator.currentLineStart; if((currentLineLength > 0)) // use previous position of separator to split text { pos = separator.currentLineEnd-1; AddCurrentLine(text, separator.currentLineEnd, separator, resultVector); } break; } DVASSERT(i); } } state = SKIP; break; } else { DVASSERT(0); } } } if (IsSpace(t) || IsLineEnd(t)) state = SKIP; // if cur char is space go to skip else if (t == 0) state = FINISH; else if(wasSeparator && !isSeparator) { // good char after separator separator.lastWordStart = pos; separator.lastWordEnd = pos; if (!separator.IsLineInitialized()) separator.currentLineStart = pos; } } break; case FINISH: if (separator.IsLineInitialized()) // we check if we have something left in currentline and add this line to results { DVASSERT(separator.currentLineEnd > separator.currentLineStart); AddCurrentLine(text, separator.currentLineEnd, separator, resultVector); } state = EXIT; // always exit from here break; }; wasSeparator = isSeparator; }; }