XFileParser.cpp 46 KB

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