XFileParser.cpp 33 KB

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