ObjFileParser.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. #include "ObjFileParser.h"
  2. #include "ObjFileMtlImporter.h"
  3. #include "ObjTools.h"
  4. #include "ObjFileData.h"
  5. #include "DefaultIOSystem.h"
  6. #include "../include/IOStream.h"
  7. #include "../include/aiTypes.h"
  8. #include "../include/aiAssert.h"
  9. #include "fast_atof.h"
  10. #include <iostream>
  11. #include <vector>
  12. #include <cassert>
  13. namespace Assimp
  14. {
  15. // -------------------------------------------------------------------
  16. ObjFileParser::ObjFileParser(std::vector<char> &Data,
  17. const std::string &strAbsPath,
  18. const std::string &strModelName) :
  19. m_strAbsPath(strAbsPath),
  20. m_DataIt(Data.begin()),
  21. m_DataItEnd(Data.end()),
  22. m_pModel(NULL),
  23. m_uiLine(0)
  24. {
  25. // Create the model instance to store all the data
  26. m_pModel = new ObjFile::Model();
  27. m_pModel->m_ModelName = strModelName;
  28. const std::string DEFAULT_MATERIAL = "defaultmaterial";
  29. m_pModel->m_pDefaultMaterial = new ObjFile::Material();
  30. m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL );
  31. m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
  32. // Start parsing the file
  33. parseFile();
  34. }
  35. // -------------------------------------------------------------------
  36. ObjFileParser::~ObjFileParser()
  37. {
  38. // empty
  39. }
  40. // -------------------------------------------------------------------
  41. ObjFile::Model *ObjFileParser::GetModel() const
  42. {
  43. return m_pModel;
  44. }
  45. // -------------------------------------------------------------------
  46. void ObjFileParser::parseFile()
  47. {
  48. if (m_DataIt == m_DataItEnd)
  49. return;
  50. while (m_DataIt != m_DataItEnd)
  51. {
  52. switch (*m_DataIt)
  53. {
  54. case 'v': // Parse a vertex texture coordinate
  55. {
  56. ++m_DataIt;
  57. if (*m_DataIt == ' ')
  58. {
  59. // Read in vertex definition
  60. getVector3(m_pModel->m_Vertices);
  61. }
  62. else if (*m_DataIt == 't')
  63. {
  64. // Read in texture coordinate (2D)
  65. getVector2(m_pModel->m_TextureCoord);
  66. }
  67. else if (*m_DataIt == 'n')
  68. {
  69. // Read in normal vector definition
  70. getVector3(m_pModel->m_Normals);
  71. }
  72. }
  73. break;
  74. case 'f': // Parse a face
  75. {
  76. getFace();
  77. }
  78. break;
  79. case '#': // Parse a comment
  80. {
  81. getComment();
  82. }
  83. break;
  84. case 'u': // Parse a material desc. setter
  85. {
  86. getMaterialDesc();
  87. }
  88. break;
  89. case 'm': // Parse a material library
  90. {
  91. getMaterialLib();
  92. }
  93. break;
  94. case 'g': // Parse group name
  95. {
  96. getGroupName();
  97. }
  98. break;
  99. case 's': // Parse group number
  100. {
  101. getGroupNumber();
  102. }
  103. break;
  104. case 'o': // Parse object name
  105. {
  106. getObjectName();
  107. }
  108. break;
  109. default:
  110. {
  111. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  112. }
  113. break;
  114. }
  115. }
  116. }
  117. // -------------------------------------------------------------------
  118. // Copy the next word in a temporary buffer
  119. void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
  120. {
  121. size_t index = 0;
  122. m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
  123. while (!isSpace(*m_DataIt) && m_DataIt != m_DataItEnd)
  124. {
  125. pBuffer[index] = *m_DataIt;
  126. index++;
  127. if (index == length-1)
  128. break;
  129. ++m_DataIt;
  130. }
  131. pBuffer[index] = '\0';
  132. }
  133. // -------------------------------------------------------------------
  134. // Copy the next line into a temporary buffer
  135. void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
  136. {
  137. size_t index = 0;
  138. while (m_DataIt != m_DataItEnd)
  139. {
  140. if (*m_DataIt == '\n' || *m_DataIt == '\r')
  141. break;
  142. assert (index+1 <= length);
  143. pBuffer[ index ] = *m_DataIt;
  144. ++index;
  145. ++m_DataIt;
  146. }
  147. pBuffer[ index ] = '\0';
  148. }
  149. // -------------------------------------------------------------------
  150. // Get values for a new 3D vector instance
  151. void ObjFileParser::getVector3(std::vector<aiVector3D*> &point3d_array)
  152. {
  153. float x, y, z;
  154. copyNextWord(m_buffer, BUFFERSIZE);
  155. x = (float) fast_atof(m_buffer);
  156. copyNextWord(m_buffer, BUFFERSIZE);
  157. y = (float) fast_atof(m_buffer);
  158. copyNextWord(m_buffer, BUFFERSIZE);
  159. z = (float) fast_atof(m_buffer);
  160. point3d_array.push_back(new aiVector3D(x,y,z));
  161. //skipLine();
  162. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  163. }
  164. // -------------------------------------------------------------------
  165. // Get values for a new 2D vector instance
  166. void ObjFileParser::getVector2( std::vector<aiVector2D*> &point2d_array )
  167. {
  168. float x, y;
  169. copyNextWord(m_buffer, BUFFERSIZE);
  170. x = (float) fast_atof(m_buffer);
  171. copyNextWord(m_buffer, BUFFERSIZE);
  172. y = (float) fast_atof(m_buffer);
  173. point2d_array.push_back(new aiVector2D(x, y));
  174. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  175. }
  176. // -------------------------------------------------------------------
  177. // Get values for a new face instance
  178. void ObjFileParser::getFace()
  179. {
  180. copyNextLine(m_buffer, BUFFERSIZE);
  181. if (m_DataIt == m_DataItEnd)
  182. return;
  183. char *pPtr = m_buffer;
  184. char *pEnd = &pPtr[BUFFERSIZE];
  185. pPtr = getNextToken<char*>(pPtr, pEnd);
  186. if (pPtr == '\0')
  187. return;
  188. std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
  189. std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
  190. std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
  191. bool vt = (!m_pModel->m_TextureCoord.empty());
  192. bool vn = (!m_pModel->m_Normals.empty());
  193. int iStep = 0, iPos = 0;
  194. while (pPtr != pEnd)
  195. {
  196. iStep = 1;
  197. if (*pPtr == '\0')
  198. break;
  199. if (*pPtr=='\r')
  200. break;
  201. if (*pPtr=='/' )
  202. {
  203. if (iPos == 0)
  204. {
  205. //if there are no texturecoordinates in the obj file but normals
  206. if (!vt && vn)
  207. iPos = 1;
  208. }
  209. iPos++;
  210. }
  211. else if (isSpace(*pPtr))
  212. {
  213. iPos = 0;
  214. }
  215. else
  216. {
  217. //OBJ USES 1 Base ARRAYS!!!!
  218. const int iVal = atoi(pPtr);
  219. int tmp = iVal;
  220. while ((tmp = tmp / 10)!=0)
  221. ++iStep;
  222. if (0 != iVal)
  223. {
  224. // Store parsed index
  225. if (0 == iPos)
  226. {
  227. pIndices->push_back(iVal-1);
  228. }
  229. else if (1 == iPos)
  230. {
  231. pTexID->push_back(iVal-1);
  232. }
  233. else if (2 == iPos)
  234. {
  235. pNormalID->push_back(iVal-1);
  236. }
  237. else
  238. {
  239. reportErrorTokenInFace();
  240. }
  241. }
  242. }
  243. for (int i=0; i<iStep; i++)
  244. ++pPtr;
  245. }
  246. ObjFile::Face *face = new ObjFile::Face(pIndices, pNormalID, pTexID);
  247. // Set active material, if one set
  248. if (NULL != m_pModel->m_pCurrentMaterial)
  249. face->m_pMaterial = m_pModel->m_pCurrentMaterial;
  250. else
  251. face->m_pMaterial = m_pModel->m_pDefaultMaterial;
  252. // Create a default object, if nothing there
  253. if (NULL == m_pModel->m_pCurrent)
  254. createObject("defaultobject");
  255. // Store the new instance
  256. m_pModel->m_pCurrent->m_Faces.push_back(face);
  257. // Assign face to mesh
  258. if ( NULL == m_pModel->m_pCurrentMesh )
  259. {
  260. m_pModel->m_pCurrentMesh = new ObjFile::Mesh();
  261. m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
  262. }
  263. m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
  264. // Skip the rest of the line
  265. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  266. }
  267. // -------------------------------------------------------------------
  268. // Get values for a new material description
  269. void ObjFileParser::getMaterialDesc()
  270. {
  271. // Get next data for material data
  272. m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  273. if (m_DataIt == m_DataItEnd)
  274. return;
  275. char *pStart = &(*m_DataIt);
  276. while ( !isSpace(*m_DataIt) && m_DataIt != m_DataItEnd )
  277. ++m_DataIt;
  278. // Get name
  279. std::string strName(pStart, &(*m_DataIt));
  280. if ( strName.empty() )
  281. return;
  282. // Search for material
  283. std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName );
  284. if ( it == m_pModel->m_MaterialMap.end() )
  285. {
  286. // Not found, use default material
  287. m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
  288. m_pModel->m_MaterialMap[ strName ] = m_pModel->m_pCurrentMaterial;
  289. }
  290. else
  291. {
  292. // Found, using detected material
  293. m_pModel->m_pCurrentMaterial = (*it).second;
  294. // Create a new mesh for a new material
  295. m_pModel->m_pCurrentMesh = new ObjFile::Mesh();
  296. m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
  297. }
  298. // Skip rest of line
  299. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  300. }
  301. // -------------------------------------------------------------------
  302. // Get a comment, values will be skipped
  303. void ObjFileParser::getComment()
  304. {
  305. while (true)
  306. {
  307. if ('\n' == (*m_DataIt) || m_DataIt == m_DataItEnd)
  308. {
  309. ++m_DataIt;
  310. break;
  311. }
  312. else
  313. {
  314. ++m_DataIt;
  315. }
  316. }
  317. }
  318. // -------------------------------------------------------------------
  319. // Get material library from file.
  320. void ObjFileParser::getMaterialLib()
  321. {
  322. // Translate tuple
  323. m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  324. if (m_DataIt == m_DataItEnd)
  325. return;
  326. char *pStart = &(*m_DataIt);
  327. while (!isSpace(*m_DataIt))
  328. m_DataIt++;
  329. // Check for existence
  330. DefaultIOSystem IOSystem;
  331. std::string strMatName(pStart, &(*m_DataIt));
  332. std::string absName = m_strAbsPath + IOSystem.getOsSeparator() + strMatName;
  333. if ( !IOSystem.Exists(absName) )
  334. {
  335. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  336. return;
  337. }
  338. // Extract the extention
  339. std::string strExt("");
  340. extractExtension(strMatName, strExt);
  341. std::string mat = "mtl";
  342. // Load the material library
  343. DefaultIOSystem FileSystem;
  344. IOStream *pFile = FileSystem.Open(absName);
  345. if (0L != pFile)
  346. {
  347. size_t size = pFile->FileSize();
  348. std::vector<char> buffer;
  349. buffer.resize( size );
  350. size_t read_size = pFile->Read( &buffer[ 0 ], sizeof( char ), size );
  351. FileSystem.Close( pFile );
  352. // Importing the material library
  353. ObjFileMtlImporter mtlImporter( buffer, absName, m_pModel );
  354. m_pModel->m_MaterialLib.push_back( strMatName );
  355. }
  356. // Skip rest of line
  357. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  358. }
  359. // -------------------------------------------------------------------
  360. // Set a new material definition as the current material.
  361. void ObjFileParser::getNewMaterial()
  362. {
  363. m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  364. m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
  365. char *pStart = &(*m_DataIt);
  366. std::string strMat(pStart, *m_DataIt);
  367. while (isSpace(*m_DataIt))
  368. m_DataIt++;
  369. std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find(strMat);
  370. if (it == m_pModel->m_MaterialMap.end())
  371. {
  372. // Show a warning, if material was not found
  373. std::string strWarn ("Unsupported material requested: ");
  374. strWarn += strMat;
  375. std::cerr << "Warning : " << strWarn << std::endl;
  376. m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
  377. }
  378. else
  379. {
  380. // Set new material
  381. m_pModel->m_pCurrentMaterial = (*it).second;
  382. }
  383. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  384. }
  385. // -------------------------------------------------------------------
  386. // Getter for a group name.
  387. void ObjFileParser::getGroupName()
  388. {
  389. // Get next word from data buffer
  390. m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  391. m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
  392. // Store groupname in group library
  393. char *pStart = &(*m_DataIt);
  394. while (!isSpace(*m_DataIt))
  395. m_DataIt++;
  396. std::string strGroupName(pStart, &(*m_DataIt));
  397. // Change active group, if necessary
  398. if (m_pModel->m_strActiveGroup != strGroupName)
  399. {
  400. // Search for already existing entry
  401. ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName);
  402. // New group name, creating a new entry
  403. ObjFile::Object *pObject = m_pModel->m_pCurrent;
  404. if (it == m_pModel->m_Groups.end())
  405. {
  406. std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
  407. m_pModel->m_Groups[ &strGroupName ] = pFaceIDArray;
  408. m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
  409. }
  410. else
  411. {
  412. m_pModel->m_pGroupFaceIDs = (*it).second;
  413. }
  414. m_pModel->m_strActiveGroup = strGroupName;
  415. }
  416. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  417. }
  418. // -------------------------------------------------------------------
  419. // Not supported
  420. void ObjFileParser::getGroupNumber()
  421. {
  422. // Not used
  423. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  424. }
  425. // -------------------------------------------------------------------
  426. // Stores values for a new object instance, name will be used to
  427. // identify it.
  428. void ObjFileParser::getObjectName()
  429. {
  430. m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  431. if (m_DataIt == m_DataItEnd)
  432. return;
  433. char *pStart = &(*m_DataIt);
  434. while (!isSpace(*m_DataIt))
  435. m_DataIt++;
  436. std::string strObjectName(pStart, &(*m_DataIt));
  437. if (!strObjectName.empty())
  438. {
  439. // Reset current object
  440. m_pModel->m_pCurrent = NULL;
  441. // Search for actual object
  442. for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin();
  443. it != m_pModel->m_Objects.end();
  444. ++it)
  445. {
  446. if ((*it)->m_strObjName == strObjectName)
  447. {
  448. m_pModel->m_pCurrent = *it;
  449. break;
  450. }
  451. }
  452. // Allocate a new object, if current one wasn´t found before
  453. if (m_pModel->m_pCurrent == NULL)
  454. {
  455. createObject(strObjectName);
  456. /*m_pModel->m_pCurrent = new ObjFile::Object();
  457. m_pModel->m_pCurrent->m_strObjName = strObjectName;
  458. m_pModel->m_Objects.push_back(m_pModel->m_pCurrent);*/
  459. }
  460. }
  461. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  462. }
  463. // -------------------------------------------------------------------
  464. // Creates a new object instance
  465. void ObjFileParser::createObject(const std::string &strObjectName)
  466. {
  467. ai_assert (NULL != m_pModel);
  468. ai_assert (!strObjectName.empty());
  469. m_pModel->m_pCurrent = new ObjFile::Object();
  470. m_pModel->m_pCurrent->m_strObjName = strObjectName;
  471. m_pModel->m_Objects.push_back(m_pModel->m_pCurrent);
  472. }
  473. // -------------------------------------------------------------------
  474. // Shows an error in parsing process.
  475. void ObjFileParser::reportErrorTokenInFace()
  476. {
  477. std::string strErr("");
  478. m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
  479. std::cerr << "Not supported token in face desc. detected : " << strErr << std::endl;
  480. }
  481. // -------------------------------------------------------------------
  482. // Extracts the extention from a filename
  483. void ObjFileParser::extractExtension(const std::string strFile,
  484. std::string &strExt)
  485. {
  486. strExt = "";
  487. if (strFile.empty())
  488. return;
  489. std::string::size_type pos = strFile.find_last_of(".");
  490. if (pos == std::string::npos)
  491. return;
  492. strExt = strFile.substr(pos, strFile.size() - pos);
  493. }
  494. // -------------------------------------------------------------------
  495. } // Namespace Assimp