XFileParser.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /** @file Implementation of the XFile parser helper class */
  2. #include "XFileParser.h"
  3. #include "XFileHelper.h"
  4. #include "BaseImporter.h"
  5. #include "fast_atof.h"
  6. #include <boost/format.hpp>
  7. using namespace Assimp;
  8. using namespace Assimp::XFile;
  9. // ------------------------------------------------------------------------------------------------
  10. // Constructor. Creates a data structure out of the XFile given in the memory block.
  11. XFileParser::XFileParser( const std::vector<char>& pBuffer)
  12. {
  13. mMajorVersion = mMinorVersion = 0;
  14. mIsBinaryFormat = false;
  15. mBinaryNumCount = 0;
  16. P = End = NULL;
  17. mLineNumber = 0;
  18. mScene = NULL;
  19. // set up memory pointers
  20. P = &pBuffer.front();
  21. End = P + pBuffer.size();
  22. // check header
  23. if( strncmp( P, "xof ", 4) != 0)
  24. throw new ImportErrorException( "Header mismatch, file is not an XFile.");
  25. // read version. It comes in a four byte format such as "0302"
  26. mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48);
  27. mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48);
  28. // read format
  29. if( strncmp( P + 8, "txt ", 4) == 0)
  30. mIsBinaryFormat = false;
  31. else if( strncmp( P + 8, "bin ", 4) == 0)
  32. mIsBinaryFormat = true;
  33. else
  34. ThrowException( "Unsupported xfile format");
  35. // float size
  36. mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000
  37. + (unsigned int)(P[13] - 48) * 100
  38. + (unsigned int)(P[14] - 48) * 10
  39. + (unsigned int)(P[15] - 48);
  40. if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
  41. ThrowException( boost::str( boost::format( "Unknown float size %1% specified in xfile header.") % mBinaryFloatSize));
  42. // start reading here
  43. P += 16;
  44. ReadUntilEndOfLine();
  45. mScene = new Scene;
  46. ParseFile();
  47. // filter the imported hierarchy for some degenerated cases
  48. if( mScene->mRootNode)
  49. FilterHierarchy( mScene->mRootNode);
  50. }
  51. // ------------------------------------------------------------------------------------------------
  52. // Destructor. Destroys all imported data along with it
  53. XFileParser::~XFileParser()
  54. {
  55. // kill everything we created
  56. delete mScene;
  57. }
  58. // ------------------------------------------------------------------------------------------------
  59. void XFileParser::ParseFile()
  60. {
  61. while( 1)
  62. {
  63. // read name of next object
  64. std::string objectName = GetNextToken();
  65. if (objectName.length() == 0)
  66. break;
  67. // parse specific object
  68. if( objectName == "template")
  69. ParseDataObjectTemplate();
  70. else
  71. if( objectName == "Frame")
  72. ParseDataObjectFrame( NULL);
  73. else
  74. if( objectName == "Mesh")
  75. {
  76. // some meshes have no frames at all
  77. Mesh* mesh = new Mesh;
  78. ParseDataObjectMesh( mesh);
  79. mScene->mGlobalMeshes.push_back( mesh);
  80. } else
  81. if( objectName == "AnimTicksPerSecond")
  82. ParseDataObjectAnimTicksPerSecond();
  83. else
  84. if( objectName == "AnimationSet")
  85. ParseDataObjectAnimationSet();
  86. else
  87. if( objectName == "Material")
  88. {
  89. // Material outside of a mesh or node
  90. Material material;
  91. ParseDataObjectMaterial( &material);
  92. mScene->mGlobalMaterials.push_back( material);
  93. } else
  94. if( objectName == "}")
  95. {
  96. // whatever?
  97. // os::Printer::log("} found in dataObject", ELL_WARNING);
  98. } else
  99. {
  100. // unknown format
  101. //os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING);
  102. ParseUnknownDataObject();
  103. }
  104. }
  105. }
  106. // ------------------------------------------------------------------------------------------------
  107. void XFileParser::ParseDataObjectTemplate()
  108. {
  109. // parse a template data object. Currently not stored.
  110. std::string name;
  111. readHeadOfDataObject( &name);
  112. // read GUID
  113. std::string guid = GetNextToken();
  114. // read and ignore data members
  115. while(true)
  116. {
  117. std::string s = GetNextToken();
  118. if( s == "}")
  119. break;
  120. if( s.length() == 0)
  121. ThrowException( "Unexpected end of file reached while parsing template definition");
  122. }
  123. }
  124. // ------------------------------------------------------------------------------------------------
  125. void XFileParser::ParseDataObjectFrame( Node* pParent)
  126. {
  127. // A coordinate frame, or "frame of reference." The Frame template
  128. // is open and can contain any object. The Direct3D extensions (D3DX)
  129. // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
  130. // Frame template instances as child objects when loading a Frame
  131. // instance.
  132. std::string name;
  133. readHeadOfDataObject(&name);
  134. // create a named node and place it at its parent, if given
  135. Node* node = new Node( pParent);
  136. node->mName = name;
  137. if( pParent)
  138. {
  139. pParent->mChildren.push_back( node);
  140. } else
  141. {
  142. // there might be multiple root nodes
  143. if( mScene->mRootNode != NULL)
  144. {
  145. // place a dummy root if not there
  146. if( mScene->mRootNode->mName != "$dummy_root")
  147. {
  148. Node* exroot = mScene->mRootNode;
  149. mScene->mRootNode = new Node( NULL);
  150. mScene->mRootNode->mName = "$dummy_root";
  151. mScene->mRootNode->mChildren.push_back( exroot);
  152. exroot->mParent = mScene->mRootNode;
  153. }
  154. // put the new node as its child instead
  155. mScene->mRootNode->mChildren.push_back( node);
  156. node->mParent = mScene->mRootNode;
  157. } else
  158. {
  159. // it's the first node imported. place it as root
  160. mScene->mRootNode = node;
  161. }
  162. }
  163. // Now inside a frame.
  164. // read tokens until closing brace is reached.
  165. while(true)
  166. {
  167. std::string objectName = GetNextToken();
  168. if (objectName.size() == 0)
  169. ThrowException( "Unexpected end of file reached while parsing frame");
  170. if( objectName == "}")
  171. break; // frame finished
  172. else
  173. if( objectName == "Frame")
  174. ParseDataObjectFrame( node); // child frame
  175. else
  176. if( objectName == "FrameTransformMatrix")
  177. ParseDataObjectTransformationMatrix( node->mTrafoMatrix);
  178. else
  179. if( objectName == "Mesh")
  180. {
  181. Mesh* mesh = new Mesh;
  182. node->mMeshes.push_back( mesh);
  183. ParseDataObjectMesh( mesh);
  184. } else
  185. {
  186. // os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING);
  187. ParseUnknownDataObject();
  188. }
  189. }
  190. }
  191. // ------------------------------------------------------------------------------------------------
  192. void XFileParser::ParseDataObjectTransformationMatrix( aiMatrix4x4& pMatrix)
  193. {
  194. // read header, we're not interested if it has a name
  195. readHeadOfDataObject();
  196. // read its components
  197. pMatrix.a1 = ReadFloat(); pMatrix.b1 = ReadFloat();
  198. pMatrix.c1 = ReadFloat(); pMatrix.d1 = ReadFloat();
  199. pMatrix.a2 = ReadFloat(); pMatrix.b2 = ReadFloat();
  200. pMatrix.c2 = ReadFloat(); pMatrix.d2 = ReadFloat();
  201. pMatrix.a3 = ReadFloat(); pMatrix.b3 = ReadFloat();
  202. pMatrix.c3 = ReadFloat(); pMatrix.d3 = ReadFloat();
  203. pMatrix.a4 = ReadFloat(); pMatrix.b4 = ReadFloat();
  204. pMatrix.c4 = ReadFloat(); pMatrix.d4 = ReadFloat();
  205. // trailing symbols
  206. CheckForSemicolon();
  207. CheckForClosingBrace();
  208. }
  209. // ------------------------------------------------------------------------------------------------
  210. void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
  211. {
  212. std::string name;
  213. readHeadOfDataObject( &name);
  214. // read vertex count
  215. unsigned int numVertices = ReadInt();
  216. pMesh->mPositions.resize( numVertices);
  217. // read vertices
  218. for( unsigned int a = 0; a < numVertices; a++)
  219. pMesh->mPositions[a] = ReadVector3();
  220. // read position faces
  221. unsigned int numPosFaces = ReadInt();
  222. pMesh->mPosFaces.resize( numPosFaces);
  223. for( unsigned int a = 0; a < numPosFaces; a++)
  224. {
  225. unsigned int numIndices = ReadInt();
  226. if( numIndices < 3)
  227. ThrowException( boost::str( boost::format( "Invalid index count %1% for face %2%.") % numIndices % a));
  228. // read indices
  229. Face& face = pMesh->mPosFaces[a];
  230. for( unsigned int b = 0; b < numIndices; b++)
  231. face.mIndices.push_back( ReadInt());
  232. CheckForSeparator();
  233. }
  234. // here, other data objects may follow
  235. while(true)
  236. {
  237. std::string objectName = GetNextToken();
  238. if( objectName.size() == 0)
  239. ThrowException( "Unexpected end of file while parsing mesh structure");
  240. else
  241. if( objectName == "}")
  242. break; // mesh finished
  243. else
  244. if( objectName == "MeshNormals")
  245. ParseDataObjectMeshNormals( pMesh);
  246. else
  247. if( objectName == "MeshTextureCoords")
  248. ParseDataObjectMeshTextureCoords( pMesh);
  249. else
  250. if( objectName == "MeshVertexColors")
  251. ParseDataObjectMeshVertexColors( pMesh);
  252. else
  253. if( objectName == "MeshMaterialList")
  254. ParseDataObjectMeshMaterialList( pMesh);
  255. else
  256. if( objectName == "VertexDuplicationIndices")
  257. ParseUnknownDataObject(); // we'll ignore vertex duplication indices
  258. else
  259. if( objectName == "XSkinMeshHeader")
  260. ParseDataObjectSkinMeshHeader( pMesh);
  261. else
  262. if( objectName == "SkinWeights")
  263. ParseDataObjectSkinWeights( pMesh);
  264. else
  265. {
  266. //os::Printer::log("Unknown data object in mesh in x file", objectName.c_str(), ELL_WARNING);
  267. ParseUnknownDataObject();
  268. }
  269. }
  270. }
  271. // ------------------------------------------------------------------------------------------------
  272. void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh)
  273. {
  274. readHeadOfDataObject();
  275. std::string transformNodeName;
  276. GetNextTokenAsString( transformNodeName);
  277. pMesh->mBones.push_back( Bone());
  278. Bone& bone = pMesh->mBones.back();
  279. bone.mName = transformNodeName;
  280. // read vertex weights
  281. unsigned int numWeights = ReadInt();
  282. bone.mWeights.reserve( numWeights);
  283. for( unsigned int a = 0; a < numWeights; a++)
  284. {
  285. BoneWeight weight;
  286. weight.mVertex = ReadInt();
  287. bone.mWeights.push_back( weight);
  288. }
  289. // read vertex weights
  290. for( unsigned int a = 0; a < numWeights; a++)
  291. bone.mWeights[a].mWeight = ReadFloat();
  292. // read matrix offset
  293. bone.mOffsetMatrix.a1 = ReadFloat(); bone.mOffsetMatrix.b1 = ReadFloat();
  294. bone.mOffsetMatrix.c1 = ReadFloat(); bone.mOffsetMatrix.d1 = ReadFloat();
  295. bone.mOffsetMatrix.a2 = ReadFloat(); bone.mOffsetMatrix.b2 = ReadFloat();
  296. bone.mOffsetMatrix.c2 = ReadFloat(); bone.mOffsetMatrix.d2 = ReadFloat();
  297. bone.mOffsetMatrix.a3 = ReadFloat(); bone.mOffsetMatrix.b3 = ReadFloat();
  298. bone.mOffsetMatrix.c3 = ReadFloat(); bone.mOffsetMatrix.d3 = ReadFloat();
  299. bone.mOffsetMatrix.a4 = ReadFloat(); bone.mOffsetMatrix.b4 = ReadFloat();
  300. bone.mOffsetMatrix.c4 = ReadFloat(); bone.mOffsetMatrix.d4 = ReadFloat();
  301. CheckForSemicolon();
  302. CheckForClosingBrace();
  303. }
  304. // ------------------------------------------------------------------------------------------------
  305. void XFileParser::ParseDataObjectSkinMeshHeader( Mesh* pMesh)
  306. {
  307. readHeadOfDataObject();
  308. unsigned int maxSkinWeightsPerVertex = ReadInt();
  309. unsigned int maxSkinWeightsPerFace = ReadInt();
  310. unsigned int numBonesInMesh = ReadInt();
  311. CheckForClosingBrace();
  312. }
  313. // ------------------------------------------------------------------------------------------------
  314. void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh)
  315. {
  316. readHeadOfDataObject();
  317. // read count
  318. unsigned int numNormals = ReadInt();
  319. pMesh->mNormals.resize( numNormals);
  320. // read normal vectors
  321. for( unsigned int a = 0; a < numNormals; a++)
  322. pMesh->mNormals[a] = ReadVector3();
  323. // read normal indices
  324. unsigned int numFaces = ReadInt();
  325. if( numFaces != pMesh->mPosFaces.size())
  326. ThrowException( "Normal face count does not match vertex face count.");
  327. for( unsigned int a = 0; a < numFaces; a++)
  328. {
  329. unsigned int numIndices = ReadInt();
  330. pMesh->mNormFaces.push_back( Face());
  331. Face& face = pMesh->mNormFaces.back();
  332. for( unsigned int b = 0; b < numIndices; b++)
  333. face.mIndices.push_back( ReadInt());
  334. CheckForSeparator();
  335. }
  336. CheckForClosingBrace();
  337. }
  338. // ------------------------------------------------------------------------------------------------
  339. void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh)
  340. {
  341. readHeadOfDataObject();
  342. std::vector<aiVector2D>& coords = pMesh->mTexCoords[pMesh->mNumTextures++];
  343. unsigned int numCoords = ReadInt();
  344. if( numCoords != pMesh->mPositions.size())
  345. ThrowException( "Texture coord count does not match vertex count");
  346. coords.resize( numCoords);
  347. for( unsigned int a = 0; a < numCoords; a++)
  348. coords[a] = ReadVector2();
  349. CheckForClosingBrace();
  350. }
  351. // ------------------------------------------------------------------------------------------------
  352. void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
  353. {
  354. readHeadOfDataObject();
  355. std::vector<aiColor4D>& colors = pMesh->mColors[pMesh->mNumColorSets++];
  356. unsigned int numColors = ReadInt();
  357. if( numColors != pMesh->mPositions.size())
  358. ThrowException( "Vertex color count does not match vertex count");
  359. colors.resize( numColors, aiColor4D( 0, 0, 0, 1));
  360. for( unsigned int a = 0; a < numColors; a++)
  361. {
  362. unsigned int index = ReadInt();
  363. if( index >= pMesh->mPositions.size())
  364. ThrowException( "Vertex color index out of bounds");
  365. colors[index] = ReadRGBA();
  366. }
  367. CheckForSemicolon();
  368. CheckForClosingBrace();
  369. }
  370. // ------------------------------------------------------------------------------------------------
  371. void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
  372. {
  373. readHeadOfDataObject();
  374. // read material count
  375. unsigned int numMaterials = ReadInt();
  376. // read non triangulated face material index count
  377. unsigned int numMatIndices = ReadInt();
  378. // some models have a material index count of 1... to be able to read them we
  379. // replicate this single material index on every face
  380. if( numMatIndices != pMesh->mPosFaces.size() && numMatIndices != 1)
  381. ThrowException( "Per-Face material index count does not match face count.");
  382. // read per-face material indices
  383. for( unsigned int a = 0; a < numMatIndices; a++)
  384. pMesh->mFaceMaterials.push_back( ReadInt());
  385. // in version 03.02, the face indices end with two semicolons.
  386. // commented out version check, as version 03.03 exported from blender also has 2 semicolons
  387. if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
  388. {
  389. if( *P == ';')
  390. ++P;
  391. }
  392. // if there was only a single material index, replicate it on all faces
  393. while( pMesh->mFaceMaterials.size() < pMesh->mPosFaces.size())
  394. pMesh->mFaceMaterials.push_back( pMesh->mFaceMaterials.front());
  395. // read following data objects
  396. while(true)
  397. {
  398. std::string objectName = GetNextToken();
  399. if( objectName.size() == 0)
  400. ThrowException( "Unexpected end of file while parsing mesh material list.");
  401. else
  402. if( objectName == "}")
  403. break; // material list finished
  404. else
  405. if( objectName == "{")
  406. {
  407. // template materials
  408. std::string matName = GetNextToken();
  409. Material material;
  410. material.mIsReference = true;
  411. material.mName = matName;
  412. pMesh->mMaterials.push_back( material);
  413. CheckForClosingBrace(); // skip }
  414. } else
  415. if( objectName == "Material")
  416. {
  417. pMesh->mMaterials.push_back( Material());
  418. ParseDataObjectMaterial( &pMesh->mMaterials.back());
  419. } else
  420. if( objectName == ";")
  421. {
  422. // ignore
  423. } else
  424. {
  425. // os::Printer::log("Unknown data object in material list in x file", objectName.c_str(), ELL_WARNING);
  426. ParseUnknownDataObject();
  427. }
  428. }
  429. }
  430. // ------------------------------------------------------------------------------------------------
  431. void XFileParser::ParseDataObjectMaterial( Material* pMaterial)
  432. {
  433. std::string matName;
  434. readHeadOfDataObject( &matName);
  435. pMaterial->mName = matName;
  436. pMaterial->mIsReference = false;
  437. // read material values
  438. pMaterial->mDiffuse = ReadRGBA();
  439. pMaterial->mSpecularExponent = ReadFloat();
  440. pMaterial->mSpecular = ReadRGB();
  441. pMaterial->mEmissive = ReadRGB();
  442. // read other data objects
  443. while(true)
  444. {
  445. std::string objectName = GetNextToken();
  446. if( objectName.size() == 0)
  447. ThrowException( "Unexpected end of file while parsing mesh material");
  448. else
  449. if( objectName == "}")
  450. break; // material finished
  451. else
  452. if( objectName == "TextureFilename" || objectName == "TextureFileName")
  453. {
  454. // some exporters write "TextureFileName" instead.
  455. std::string texname;
  456. ParseDataObjectTextureFilename( texname);
  457. pMaterial->mTextures.push_back( texname);
  458. } else
  459. {
  460. // os::Printer::log("Unknown data object in material in .x file", objectName.c_str(), ELL_WARNING);
  461. ParseUnknownDataObject();
  462. }
  463. }
  464. }
  465. // ------------------------------------------------------------------------------------------------
  466. void XFileParser::ParseDataObjectAnimTicksPerSecond()
  467. {
  468. readHeadOfDataObject();
  469. mScene->mAnimTicksPerSecond = ReadInt();
  470. CheckForClosingBrace();
  471. }
  472. // ------------------------------------------------------------------------------------------------
  473. void XFileParser::ParseDataObjectAnimationSet()
  474. {
  475. std::string animName;
  476. readHeadOfDataObject( &animName);
  477. Animation* anim = new Animation;
  478. mScene->mAnims.push_back( anim);
  479. anim->mName = animName;
  480. while(true)
  481. {
  482. std::string objectName = GetNextToken();
  483. if( objectName.length() == 0)
  484. ThrowException( "Unexpected end of file while parsing animation set.");
  485. else
  486. if( objectName == "}")
  487. break; // animation set finished
  488. else
  489. if( objectName == "Animation")
  490. ParseDataObjectAnimation( anim);
  491. else
  492. {
  493. // os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING);
  494. ParseUnknownDataObject();
  495. }
  496. }
  497. }
  498. // ------------------------------------------------------------------------------------------------
  499. void XFileParser::ParseDataObjectAnimation( Animation* pAnim)
  500. {
  501. readHeadOfDataObject();
  502. AnimBone* banim = new AnimBone;
  503. pAnim->mAnims.push_back( banim);
  504. while(true)
  505. {
  506. std::string objectName = GetNextToken();
  507. if( objectName.length() == 0)
  508. ThrowException( "Unexpected end of file while parsing animation.");
  509. else
  510. if( objectName == "}")
  511. break; // animation finished
  512. else
  513. if( objectName == "AnimationKey")
  514. ParseDataObjectAnimationKey( banim);
  515. else
  516. if( objectName == "AnimationOptions")
  517. ParseUnknownDataObject(); // not interested
  518. else
  519. if( objectName == "{")
  520. {
  521. // read frame name
  522. banim->mBoneName = GetNextToken();
  523. CheckForClosingBrace();
  524. } else
  525. {
  526. //os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING);
  527. ParseUnknownDataObject();
  528. }
  529. }
  530. }
  531. // ------------------------------------------------------------------------------------------------
  532. void XFileParser::ParseDataObjectAnimationKey( AnimBone* pAnimBone)
  533. {
  534. readHeadOfDataObject();
  535. // read key type
  536. unsigned int keyType = ReadInt();
  537. // read number of keys
  538. unsigned int numKeys = ReadInt();
  539. for( unsigned int a = 0; a < numKeys; a++)
  540. {
  541. // read time
  542. unsigned int time = ReadInt();
  543. // read keys
  544. switch( keyType)
  545. {
  546. case 0: // rotation quaternion
  547. {
  548. // read count
  549. if( ReadInt() != 4)
  550. ThrowException( "Invalid number of arguments for quaternion key in animation");
  551. aiQuatKey key;
  552. key.mTime = double( time);
  553. key.mValue.w = ReadFloat();
  554. key.mValue.x = ReadFloat();
  555. key.mValue.y = ReadFloat();
  556. key.mValue.z = ReadFloat();
  557. pAnimBone->mRotKeys.push_back( key);
  558. CheckForSemicolon();
  559. break;
  560. }
  561. case 1: // scale vector
  562. case 2: // position vector
  563. {
  564. // read count
  565. if( ReadInt() != 3)
  566. ThrowException( "Invalid number of arguments for vector key in animation");
  567. aiVectorKey key;
  568. key.mTime = double( time);
  569. key.mValue = ReadVector3();
  570. if( keyType == 2)
  571. pAnimBone->mPosKeys.push_back( key);
  572. else
  573. pAnimBone->mScaleKeys.push_back( key);
  574. break;
  575. }
  576. case 3: // combined transformation matrix
  577. case 4: // denoted both as 3 or as 4
  578. {
  579. // read count
  580. if( ReadInt() != 16)
  581. ThrowException( "Invalid number of arguments for matrix key in animation");
  582. // read matrix
  583. MatrixKey key;
  584. key.mTime = double( time);
  585. key.mMatrix.a1 = ReadFloat(); key.mMatrix.b1 = ReadFloat();
  586. key.mMatrix.c1 = ReadFloat(); key.mMatrix.d1 = ReadFloat();
  587. key.mMatrix.a2 = ReadFloat(); key.mMatrix.b2 = ReadFloat();
  588. key.mMatrix.c2 = ReadFloat(); key.mMatrix.d2 = ReadFloat();
  589. key.mMatrix.a3 = ReadFloat(); key.mMatrix.b3 = ReadFloat();
  590. key.mMatrix.c3 = ReadFloat(); key.mMatrix.d3 = ReadFloat();
  591. key.mMatrix.a4 = ReadFloat(); key.mMatrix.b4 = ReadFloat();
  592. key.mMatrix.c4 = ReadFloat(); key.mMatrix.d4 = ReadFloat();
  593. pAnimBone->mTrafoKeys.push_back( key);
  594. CheckForSemicolon();
  595. break;
  596. }
  597. default:
  598. ThrowException( boost::str( boost::format( "Unknown key type %1% in animation.") % keyType));
  599. break;
  600. } // end switch
  601. // key separator
  602. CheckForSeparator();
  603. }
  604. CheckForClosingBrace();
  605. }
  606. // ------------------------------------------------------------------------------------------------
  607. void XFileParser::ParseDataObjectTextureFilename( std::string& pName)
  608. {
  609. readHeadOfDataObject();
  610. GetNextTokenAsString( pName);
  611. CheckForClosingBrace();
  612. }
  613. // ------------------------------------------------------------------------------------------------
  614. void XFileParser::ParseUnknownDataObject()
  615. {
  616. // find opening delimiter
  617. while( true)
  618. {
  619. std::string t = GetNextToken();
  620. if( t.length() == 0)
  621. ThrowException( "Unexpected end of file while parsing unknown segment.");
  622. if( t == "{")
  623. break;
  624. }
  625. unsigned int counter = 1;
  626. // parse until closing delimiter
  627. while( counter > 0)
  628. {
  629. std::string t = GetNextToken();
  630. if( t.length() == 0)
  631. ThrowException( "Unexpected end of file while parsing unknown segment.");
  632. if( t == "{")
  633. ++counter;
  634. else
  635. if( t == "}")
  636. --counter;
  637. }
  638. }
  639. // ------------------------------------------------------------------------------------------------
  640. //! checks for closing curly brace
  641. void XFileParser::CheckForClosingBrace()
  642. {
  643. if( GetNextToken() != "}")
  644. ThrowException( "Closing brace expected.");
  645. }
  646. // ------------------------------------------------------------------------------------------------
  647. //! checks for one following semicolon
  648. void XFileParser::CheckForSemicolon()
  649. {
  650. if( mIsBinaryFormat)
  651. return;
  652. if( GetNextToken() != ";")
  653. ThrowException( "Semicolon expected.");
  654. }
  655. // ------------------------------------------------------------------------------------------------
  656. //! checks for a separator char, either a ',' or a ';'
  657. void XFileParser::CheckForSeparator()
  658. {
  659. if( mIsBinaryFormat)
  660. return;
  661. std::string token = GetNextToken();
  662. if( token != "," && token != ";")
  663. ThrowException( "Separator character (';' or ',') expected.");
  664. }
  665. // ------------------------------------------------------------------------------------------------
  666. void XFileParser::readHeadOfDataObject( std::string* poName)
  667. {
  668. std::string nameOrBrace = GetNextToken();
  669. if( nameOrBrace != "{")
  670. {
  671. if( poName)
  672. *poName = nameOrBrace;
  673. if( GetNextToken() != "{")
  674. ThrowException( "Opening brace expected.");
  675. }
  676. }
  677. // ------------------------------------------------------------------------------------------------
  678. std::string XFileParser::GetNextToken()
  679. {
  680. std::string s;
  681. // process binary-formatted file
  682. if( mIsBinaryFormat)
  683. {
  684. // in binary mode it will only return NAME and STRING token
  685. // and (correctly) skip over other tokens.
  686. unsigned int tok = ReadBinWord();
  687. unsigned int len;
  688. // standalone tokens
  689. switch( tok)
  690. {
  691. case 1:
  692. // name token
  693. len = ReadBinDWord();
  694. s = std::string(P, len);
  695. P += len;
  696. return s;
  697. case 2:
  698. // string token
  699. len = ReadBinDWord();
  700. s = std::string(P, len);
  701. P += (len + 2);
  702. return s;
  703. case 3:
  704. // integer token
  705. P += 4;
  706. return "<integer>";
  707. case 5:
  708. // GUID token
  709. P += 16;
  710. return "<guid>";
  711. case 6:
  712. len = ReadBinDWord();
  713. P += (len * 4);
  714. return "<int_list>";
  715. case 7:
  716. len = ReadBinDWord();
  717. P += (len * mBinaryFloatSize);
  718. return "<flt_list>";
  719. case 0x0a:
  720. return "{";
  721. case 0x0b:
  722. return "}";
  723. case 0x0c:
  724. return "(";
  725. case 0x0d:
  726. return ")";
  727. case 0x0e:
  728. return "[";
  729. case 0x0f:
  730. return "]";
  731. case 0x10:
  732. return "<";
  733. case 0x11:
  734. return ">";
  735. case 0x12:
  736. return ".";
  737. case 0x13:
  738. return ",";
  739. case 0x14:
  740. return ";";
  741. case 0x1f:
  742. return "template";
  743. case 0x28:
  744. return "WORD";
  745. case 0x29:
  746. return "DWORD";
  747. case 0x2a:
  748. return "FLOAT";
  749. case 0x2b:
  750. return "DOUBLE";
  751. case 0x2c:
  752. return "CHAR";
  753. case 0x2d:
  754. return "UCHAR";
  755. case 0x2e:
  756. return "SWORD";
  757. case 0x2f:
  758. return "SDWORD";
  759. case 0x30:
  760. return "void";
  761. case 0x31:
  762. return "string";
  763. case 0x32:
  764. return "unicode";
  765. case 0x33:
  766. return "cstring";
  767. case 0x34:
  768. return "array";
  769. }
  770. }
  771. // process text-formatted file
  772. else
  773. {
  774. FindNextNoneWhiteSpace();
  775. if( P >= End)
  776. return s;
  777. while( (P < End) && !isspace( (unsigned char) *P))
  778. {
  779. // either keep token delimiters when already holding a token, or return if first valid char
  780. if( *P == ';' || *P == '}' || *P == '{' || *P == ',')
  781. {
  782. if( !s.size())
  783. s.append( P++, 1);
  784. break; // stop for delimiter
  785. }
  786. s.append( P++, 1);
  787. }
  788. }
  789. return s;
  790. }
  791. // ------------------------------------------------------------------------------------------------
  792. void XFileParser::FindNextNoneWhiteSpace()
  793. {
  794. if( mIsBinaryFormat)
  795. return;
  796. while( true)
  797. {
  798. while( P < End && isspace( (unsigned char) *P))
  799. {
  800. if( *P == '\n')
  801. mLineNumber++;
  802. ++P;
  803. }
  804. if( P >= End)
  805. return;
  806. // check if this is a comment
  807. if( (P[0] == '/' && P[1] == '/') || P[0] == '#')
  808. ReadUntilEndOfLine();
  809. else
  810. break;
  811. }
  812. }
  813. // ------------------------------------------------------------------------------------------------
  814. void XFileParser::GetNextTokenAsString( std::string& poString)
  815. {
  816. if( mIsBinaryFormat)
  817. {
  818. poString = GetNextToken();
  819. return;
  820. }
  821. FindNextNoneWhiteSpace();
  822. if( P >= End)
  823. ThrowException( "Unexpected end of file while parsing string");
  824. if( *P != '"')
  825. ThrowException( "Expected quotation mark.");
  826. ++P;
  827. while( P < End && *P != '"')
  828. poString.append( P++, 1);
  829. if( P >= End-1)
  830. ThrowException( "Unexpected end of file while parsing string");
  831. if( P[1] != ';' || P[0] != '"')
  832. ThrowException( "Expected quotation mark and semicolon at the end of a string.");
  833. P+=2;
  834. }
  835. // ------------------------------------------------------------------------------------------------
  836. void XFileParser::ReadUntilEndOfLine()
  837. {
  838. if( mIsBinaryFormat)
  839. return;
  840. while( P < End)
  841. {
  842. if( *P == '\n' || *P == '\r')
  843. {
  844. ++P; mLineNumber++;
  845. return;
  846. }
  847. ++P;
  848. }
  849. }
  850. // ------------------------------------------------------------------------------------------------
  851. unsigned short XFileParser::ReadBinWord()
  852. {
  853. const unsigned char* q = (const unsigned char*) P;
  854. unsigned short tmp = q[0] | (q[1] << 8);
  855. P += 2;
  856. return tmp;
  857. }
  858. // ------------------------------------------------------------------------------------------------
  859. unsigned int XFileParser::ReadBinDWord()
  860. {
  861. const unsigned char* q = (const unsigned char*) P;
  862. unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
  863. P += 4;
  864. return tmp;
  865. }
  866. // ------------------------------------------------------------------------------------------------
  867. unsigned int XFileParser::ReadInt()
  868. {
  869. if( mIsBinaryFormat)
  870. {
  871. if( mBinaryNumCount == 0)
  872. {
  873. unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
  874. if( tmp == 0x06) // array of ints follows
  875. mBinaryNumCount = ReadBinDWord();
  876. else // single int follows
  877. mBinaryNumCount = 1;
  878. }
  879. --mBinaryNumCount;
  880. return ReadBinDWord();
  881. } else
  882. {
  883. FindNextNoneWhiteSpace();
  884. // check preceeding minus sign
  885. bool isNegative = false;
  886. if( *P == '-')
  887. {
  888. isNegative = true;
  889. P++;
  890. }
  891. // at least one digit expected
  892. if( !isdigit( *P))
  893. ThrowException( "Number expected.");
  894. // read digits
  895. unsigned int number = 0;
  896. while( P < End)
  897. {
  898. if( !isdigit( *P))
  899. break;
  900. number = number * 10 + (*P - 48);
  901. P++;
  902. }
  903. CheckForSeparator();
  904. return isNegative ? ((unsigned int) -int( number)) : number;
  905. }
  906. }
  907. // ------------------------------------------------------------------------------------------------
  908. float XFileParser::ReadFloat()
  909. {
  910. if( mIsBinaryFormat)
  911. {
  912. if( mBinaryNumCount == 0)
  913. {
  914. unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
  915. if( tmp == 0x07) // array of floats following
  916. mBinaryNumCount = ReadBinDWord();
  917. else // single float following
  918. mBinaryNumCount = 1;
  919. }
  920. --mBinaryNumCount;
  921. if( mBinaryFloatSize == 8)
  922. {
  923. float result = (float) (*(double*) P);
  924. P += 8;
  925. return result;
  926. } else
  927. {
  928. float result = *(float*) P;
  929. P += 4;
  930. return result;
  931. }
  932. }
  933. // text version
  934. FindNextNoneWhiteSpace();
  935. // check for various special strings to allow reading files from faulty exporters
  936. // I mean you, Blender!
  937. if( strncmp( P, "-1.#IND00", 9) == 0)
  938. {
  939. P += 9;
  940. CheckForSeparator();
  941. return 0.0f;
  942. } else
  943. if( strncmp( P, "1.#QNAN0", 8) == 0)
  944. {
  945. P += 8;
  946. CheckForSeparator();
  947. return 0.0f;
  948. }
  949. float result = 0.0f;
  950. P = fast_atof_move( P, result);
  951. CheckForSeparator();
  952. return result;
  953. }
  954. // ------------------------------------------------------------------------------------------------
  955. aiVector2D XFileParser::ReadVector2()
  956. {
  957. aiVector2D vector;
  958. vector.x = ReadFloat();
  959. vector.y = ReadFloat();
  960. CheckForSeparator();
  961. return vector;
  962. }
  963. // ------------------------------------------------------------------------------------------------
  964. aiVector3D XFileParser::ReadVector3()
  965. {
  966. aiVector3D vector;
  967. vector.x = ReadFloat();
  968. vector.y = ReadFloat();
  969. vector.z = ReadFloat();
  970. CheckForSeparator();
  971. return vector;
  972. }
  973. // ------------------------------------------------------------------------------------------------
  974. aiColor4D XFileParser::ReadRGBA()
  975. {
  976. aiColor4D color;
  977. color.r = ReadFloat();
  978. color.g = ReadFloat();
  979. color.b = ReadFloat();
  980. color.a = ReadFloat();
  981. CheckForSeparator();
  982. return color;
  983. }
  984. // ------------------------------------------------------------------------------------------------
  985. aiColor3D XFileParser::ReadRGB()
  986. {
  987. aiColor3D color;
  988. color.r = ReadFloat();
  989. color.g = ReadFloat();
  990. color.b = ReadFloat();
  991. CheckForSeparator();
  992. return color;
  993. }
  994. // Throws an exception with a line number and the given text.
  995. void XFileParser::ThrowException( const std::string& pText)
  996. {
  997. if( mIsBinaryFormat)
  998. throw new ImportErrorException( pText);
  999. else
  1000. throw new ImportErrorException( boost::str( boost::format( "Line %d: %s") % mLineNumber % pText));
  1001. }
  1002. // ------------------------------------------------------------------------------------------------
  1003. // Filters the imported hierarchy for some degenerated cases that some exporters produce.
  1004. void XFileParser::FilterHierarchy( XFile::Node* pNode)
  1005. {
  1006. // if the node has just a single unnamed child containing a mesh, remove
  1007. // the anonymous node inbetween. The 3DSMax kwXport plugin seems to produce this
  1008. // mess in some cases
  1009. if( pNode->mChildren.size() == 1)
  1010. {
  1011. XFile::Node* child = pNode->mChildren.front();
  1012. if( child->mName.length() == 0 && child->mMeshes.size() > 0)
  1013. {
  1014. // transfer its meshes to us
  1015. for( unsigned int a = 0; a < child->mMeshes.size(); a++)
  1016. pNode->mMeshes.push_back( child->mMeshes[a]);
  1017. child->mMeshes.clear();
  1018. // then kill it
  1019. delete child;
  1020. pNode->mChildren.clear();
  1021. }
  1022. }
  1023. // recurse
  1024. for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
  1025. FilterHierarchy( pNode->mChildren[a]);
  1026. }