123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- #include "ObjFileParser.h"
- #include "ObjTools.h"
- #include "ObjFileData.h"
- #include "DefaultIOSystem.h"
- #include "IOStream.h"
- #include "aiTypes.h"
- #include "aiVector3D.h"
- #include "aiAssert.h"
- #include "fast_atof.h"
- #include <iostream>
- #include <vector>
- #include <cassert>
- namespace Assimp
- {
- // -------------------------------------------------------------------
- ObjFileParser::ObjFileParser(std::vector<char> &Data, const std::string &strAbsPath, const std::string &strModelName) :
- m_strAbsPath(strAbsPath),
- m_DataIt(Data.begin()),
- m_DataItEnd(Data.end()),
- m_pModel(NULL),
- m_uiLine(0)
- {
- // Create the model instance to store all the data
- m_pModel = new ObjFile::Model();
- m_pModel->m_ModelName = strModelName;
-
- // Start parsing the file
- parseFile();
- }
- // -------------------------------------------------------------------
- ObjFileParser::~ObjFileParser()
- {
- // empty
- }
- // -------------------------------------------------------------------
- ObjFile::Model *ObjFileParser::GetModel() const
- {
- return m_pModel;
- }
- // -------------------------------------------------------------------
- void ObjFileParser::parseFile()
- {
- if (m_DataIt == m_DataItEnd)
- return;
- while (m_DataIt != m_DataItEnd)
- {
- switch (*m_DataIt)
- {
- case 'v': // Parse a vertex texture coordinate
- {
- ++m_DataIt;
- if (*m_DataIt == ' ')
- {
- // Read in vertex definition
- getVector3(m_pModel->m_Vertices);
- }
- else if (*m_DataIt == 't')
- {
- // Read in texture coordinate (2D)
- getVector2(m_pModel->m_TextureCoord);
- }
- else if (*m_DataIt == 'n')
- {
- // Read in normal vector definition
- getVector3(m_pModel->m_Normals);
- }
- }
- break;
- case 'f': // Parse a face
- {
- getFace();
- }
- break;
- case '#': // Parse a comment
- {
- getComment();
- }
- break;
- case 'u': // Parse a material desc. setter
- {
- getMaterialDesc();
- }
- break;
- case 'm': // Parse a material library
- {
- getMaterialLib();
- }
- break;
- case 'g': // Parse group name
- {
- getGroupName();
- }
- break;
- case 's': // Parse group number
- {
- getGroupNumber();
- }
- break;
- case 'o': // Parse object name
- {
- getObjectName();
- }
- break;
-
- default:
- {
- skipLine();
- }
- break;
- }
- }
- }
- // -------------------------------------------------------------------
- // 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 (!isSpace(*m_DataIt) && m_DataIt != m_DataItEnd)
- {
- pBuffer[index] = *m_DataIt;
- index++;
- if (index == length-1)
- break;
- ++m_DataIt;
- }
- pBuffer[index] = '\0';
- }
- // -------------------------------------------------------------------
- // Copy the next line into a temporary buffer
- void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
- {
- size_t index = 0;
- while (m_DataIt != m_DataItEnd)
- {
- if (*m_DataIt == '\n' || *m_DataIt == '\r')
- break;
- assert (index+1 <= length);
- pBuffer[ index ] = *m_DataIt;
- ++index;
- ++m_DataIt;
- }
- pBuffer[ index ] = '\0';
- }
- // -------------------------------------------------------------------
- // Get values for a new 3D vector instance
- void ObjFileParser::getVector3(std::vector<aiVector3D_t*> &point3d_array)
- {
- float x, y, z;
- 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);
- point3d_array.push_back(new aiVector3D(x,y,z));
- skipLine();
- }
- // -------------------------------------------------------------------
- // Get values for a new 2D vector instance
- void ObjFileParser::getVector2(std::vector<aiVector2D_t*> &point2d_array)
- {
- float x, y;
- copyNextWord(m_buffer, BUFFERSIZE);
- x = (float) fast_atof(m_buffer);
-
- copyNextWord(m_buffer, BUFFERSIZE);
- y = (float) fast_atof(m_buffer);
- point2d_array.push_back(new aiVector2D(x, y));
- skipLine();
- }
- // -------------------------------------------------------------------
- // Skips a line
- void ObjFileParser::skipLine()
- {
- while (m_DataIt != m_DataItEnd && *m_DataIt != '\n')
- ++m_DataIt;
- if (m_DataIt != m_DataItEnd)
- {
- ++m_DataIt;
- ++m_uiLine;
- }
- }
- // -------------------------------------------------------------------
- // Get values for a new face instance
- void ObjFileParser::getFace()
- {
- 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 == '\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 vt = (!m_pModel->m_TextureCoord.empty());
- bool vn = (!m_pModel->m_Normals.empty());
- int iStep = 0, iPos = 0;
- while (pPtr != pEnd)
- {
- iStep = 1;
- if (*pPtr == '\0')
- break;
- if (*pPtr=='\r')
- break;
- if (*pPtr=='/' )
- {
- if (iPos == 0)
- {
- //if there are no texturecoordinates in the obj file but normals
- if (!vt && vn)
- iPos = 1;
- }
- iPos++;
- }
- else if (isSpace(*pPtr))
- {
- iPos = 0;
- }
- else
- {
- //OBJ USES 1 Base ARRAYS!!!!
- const int iVal = atoi(pPtr);
- int tmp = iVal;
- while ((tmp = tmp / 10)!=0)
- ++iStep;
- if (0 != iVal)
- {
- // 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);
- }
- else
- {
- reportErrorTokenInFace();
- }
- }
- }
- for (int i=0; i<iStep; i++)
- ++pPtr;
- }
- ObjFile::Face *face = new ObjFile::Face(pIndices, pNormalID, pTexID);
-
- // 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 there
- if (NULL == m_pModel->m_pCurrent)
- createObject("defaultobject");
- // Store the new instance
- m_pModel->m_pCurrent->m_Faces.push_back(face);
-
- // Skip the rest of the line
- skipLine();
- }
- // -------------------------------------------------------------------
- // 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 (!isSpace(*m_DataIt) && m_DataIt != m_DataItEnd)
- m_DataIt++;
- // Get name
- std::string strName(pStart, &(*m_DataIt));
- if (strName.empty())
- return;
- // Search for material
- std::string strFile;
- std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find(strName);
- if (it == m_pModel->m_MaterialMap.end())
- {
- m_pModel->m_pCurrentMaterial = new ObjFile::Material();
- m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial;
- }
- skipLine();
- }
- // -------------------------------------------------------------------
- // Get a comment, values will be skipped
- void ObjFileParser::getComment()
- {
- while (true)
- {
- if ('\n' == (*m_DataIt) || m_DataIt == m_DataItEnd)
- {
- ++m_DataIt;
- break;
- }
- else
- {
- ++m_DataIt;
- }
- }
- }
- // -------------------------------------------------------------------
- //
- void ObjFileParser::getMaterialLib()
- {
- // Translate tuple
- m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
- if (m_DataIt == m_DataItEnd)
- return;
-
- char *pStart = &(*m_DataIt);
- while (!isSpace(*m_DataIt))
- m_DataIt++;
-
- // Check for existence
- DefaultIOSystem IOSystem;
- std::string strMatName(pStart, &(*m_DataIt));
- std::string absName = m_strAbsPath + IOSystem.getOsSeparator() + strMatName;
- if (!IOSystem.Exists(absName))
- {
- skipLine();
- return;
- }
- std::string strExt("");
- extractExtension(strMatName, strExt);
- std::string mat = "mtl";
- DefaultIOSystem FileSystem;
- IOStream *pFile = FileSystem.Open(absName);
- if (0L != pFile)
- {
- size_t size = pFile->FileSize();
- char *pBuffer = new char[size];
- size_t read_size = pFile->Read(pBuffer, sizeof(char), size);
- FileSystem.Close(pFile);
- // TODO: Load mtl file
-
- delete [] pBuffer;
-
- }
- // Load material library (all materials will be created)
- m_pModel->m_MaterialLib.push_back(strMatName);
-
- skipLine();
- }
- // -------------------------------------------------------------------
- //
- void ObjFileParser::getNewMaterial()
- {
- m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
- m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
- char *pStart = &(*m_DataIt);
- std::string strMat(pStart, *m_DataIt);
- while (isSpace(*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
- std::string strWarn ("Unsupported material requested: ");
- strWarn += strMat;
- std::cerr << "Warning : " << strWarn << std::endl;
- m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
- }
- else
- {
- // Set new material
- m_pModel->m_pCurrentMaterial = (*it).second;
- }
- skipLine();
- }
- // -------------------------------------------------------------------
- //
- 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);
-
- // Store groupname in group library
- char *pStart = &(*m_DataIt);
- while (!isSpace(*m_DataIt))
- m_DataIt++;
- std::string strGroupName(pStart, &(*m_DataIt));
- // Change active group, if necessary
- if (m_pModel->m_strActiveGroup != strGroupName)
- {
- // Search for already existing entry
- ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName);
-
- // New group name, creating a new entry
- ObjFile::Object *pObject = m_pModel->m_pCurrent;
- if (it == m_pModel->m_Groups.end())
- {
- std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
- m_pModel->m_Groups[ &strGroupName ] = pFaceIDArray;
- m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
- }
- else
- {
- m_pModel->m_pGroupFaceIDs = (*it).second;
- }
- m_pModel->m_strActiveGroup = strGroupName;
- }
- skipLine();
- }
- // -------------------------------------------------------------------
- // Not supported
- void ObjFileParser::getGroupNumber()
- {
- // TODO: Implement this
- skipLine();
- }
- // -------------------------------------------------------------------
- // 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 (!isSpace(*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 wasn´t found before
- if (m_pModel->m_pCurrent == NULL)
- {
- createObject(strObjectName);
- /*m_pModel->m_pCurrent = new ObjFile::Object();
- m_pModel->m_pCurrent->m_strObjName = strObjectName;
- m_pModel->m_Objects.push_back(m_pModel->m_pCurrent);*/
- }
- }
- skipLine();
- }
- // -------------------------------------------------------------------
- // Creates a new object instance
- void ObjFileParser::createObject(const std::string &strObjectName)
- {
- ai_assert (NULL != m_pModel);
- ai_assert (!strObjectName.empty());
- m_pModel->m_pCurrent = new ObjFile::Object();
- m_pModel->m_pCurrent->m_strObjName = strObjectName;
- m_pModel->m_Objects.push_back(m_pModel->m_pCurrent);
- }
- // -------------------------------------------------------------------
- // Shows an error in parsing process.
- void ObjFileParser::reportErrorTokenInFace()
- {
- std::string strErr("");
- skipLine();
- std::cerr << "Not supported token in face desc. detected : " << strErr << std::endl;
- }
- // -------------------------------------------------------------------
- // Extracts the extention from a filename
- void ObjFileParser::extractExtension(const std::string strFile,
- std::string &strExt)
- {
- strExt = "";
- if (strFile.empty())
- return;
- std::string::size_type pos = strFile.find_last_of(".");
- if (pos == std::string::npos)
- return;
- strExt = strFile.substr(pos, strFile.size() - pos);
- }
- // -------------------------------------------------------------------
- } // Namespace Assimp
|