XFileParser.cpp 38 KB

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