3DSLoader.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350
  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 3ds importer class */
  35. // internal headers
  36. #include "3DSLoader.h"
  37. #include "MaterialSystem.h"
  38. #include "TextureTransform.h"
  39. #include "StringComparison.h"
  40. #include "qnan.h"
  41. // public ASSIMP headers
  42. #include "../include/DefaultLogger.h"
  43. #include "../include/IOStream.h"
  44. #include "../include/IOSystem.h"
  45. #include "../include/aiMesh.h"
  46. #include "../include/aiScene.h"
  47. #include "../include/aiAssert.h"
  48. // boost headers
  49. #include <boost/scoped_ptr.hpp>
  50. using namespace Assimp;
  51. #if (!defined ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG)
  52. # define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
  53. "WARNING: Size of chunk data plus size of " \
  54. "subordinate chunks is larger than the size " \
  55. "specified in the top-level chunk header."
  56. #endif
  57. // ------------------------------------------------------------------------------------------------
  58. // Constructor to be privately used by Importer
  59. Dot3DSImporter::Dot3DSImporter()
  60. {
  61. }
  62. // ------------------------------------------------------------------------------------------------
  63. // Destructor, private as well
  64. Dot3DSImporter::~Dot3DSImporter()
  65. {
  66. }
  67. // ------------------------------------------------------------------------------------------------
  68. // Returns whether the class can handle the format of the given file.
  69. bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
  70. {
  71. // simple check of file extension is enough for the moment
  72. std::string::size_type pos = pFile.find_last_of('.');
  73. // no file extension - can't read
  74. if( pos == std::string::npos)
  75. return false;
  76. std::string extension = pFile.substr( pos);
  77. // not brilliant but working ;-)
  78. if( extension == ".3ds" || extension == ".3DS" ||
  79. extension == ".3Ds" || extension == ".3dS")
  80. return true;
  81. return false;
  82. }
  83. // ------------------------------------------------------------------------------------------------
  84. // Imports the given file into the given scene structure.
  85. void Dot3DSImporter::InternReadFile(
  86. const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
  87. {
  88. boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
  89. // Check whether we can read from the file
  90. if( file.get() == NULL)
  91. {
  92. throw new ImportErrorException( "Failed to open file " + pFile + ".");
  93. }
  94. // check whether the .3ds file is large enough to contain
  95. // at least one chunk.
  96. size_t fileSize = file->FileSize();
  97. if( fileSize < 16)
  98. {
  99. throw new ImportErrorException( "3DS File is too small.");
  100. }
  101. this->mScene = new Dot3DS::Scene();
  102. // allocate storage and copy the contents of the file to a memory buffer
  103. this->mBuffer = new unsigned char[fileSize];
  104. file->Read( mBuffer, 1, fileSize);
  105. this->mCurrent = this->mBuffer;
  106. this->mLast = this->mBuffer+fileSize;
  107. // initialize members
  108. this->mLastNodeIndex = -1;
  109. this->mCurrentNode = new Dot3DS::Node();
  110. this->mRootNode = this->mCurrentNode;
  111. this->mRootNode->mHierarchyPos = -1;
  112. this->mRootNode->mHierarchyIndex = -1;
  113. this->mRootNode->mParent = NULL;
  114. this->mMasterScale = 1.0f;
  115. this->mBackgroundImage = "";
  116. this->bHasBG = false;
  117. int iRemaining = (unsigned int)fileSize;
  118. // parse the file
  119. try
  120. {
  121. this->ParseMainChunk(iRemaining);
  122. }
  123. catch ( ImportErrorException* ex)
  124. {
  125. delete[] this->mBuffer;
  126. throw ex;
  127. };
  128. // Generate an unique set of vertices/indices for
  129. // all meshes contained in the file
  130. for (std::vector<Dot3DS::Mesh>::iterator
  131. i = this->mScene->mMeshes.begin();
  132. i != this->mScene->mMeshes.end();++i)
  133. {
  134. // TODO: see function body
  135. this->CheckIndices(&(*i));
  136. this->MakeUnique(&(*i));
  137. // first generate normals for the mesh
  138. this->GenNormals(&(*i));
  139. }
  140. // Apply scaling and offsets to all texture coordinates
  141. TextureTransform::ApplyScaleNOffset(this->mScene->mMaterials);
  142. // Replace all occurences of the default material with a valid material.
  143. // Generate it if no material containing DEFAULT in its name has been
  144. // found in the file
  145. this->ReplaceDefaultMaterial();
  146. // Convert the scene from our internal representation to an aiScene object
  147. this->ConvertScene(pScene);
  148. // Generate the node graph for the scene. This is a little bit
  149. // tricky since we'll need to split some meshes into submeshes
  150. this->GenerateNodeGraph(pScene);
  151. // Now apply a master scaling factor to the scene
  152. this->ApplyMasterScale(pScene);
  153. delete[] this->mBuffer;
  154. delete this->mScene;
  155. return;
  156. }
  157. // ------------------------------------------------------------------------------------------------
  158. void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)
  159. {
  160. // NOTE: Some invalid files have masterscale set to 0.0
  161. if (0.0f == this->mMasterScale)
  162. {
  163. this->mMasterScale = 1.0f;
  164. }
  165. else this->mMasterScale = 1.0f / this->mMasterScale;
  166. // construct an uniform scaling matrix and multiply with it
  167. pScene->mRootNode->mTransformation *= aiMatrix4x4(
  168. this->mMasterScale,0.0f, 0.0f, 0.0f,
  169. 0.0f, this->mMasterScale,0.0f, 0.0f,
  170. 0.0f, 0.0f, this->mMasterScale,0.0f,
  171. 0.0f, 0.0f, 0.0f, 1.0f);
  172. }
  173. // ------------------------------------------------------------------------------------------------
  174. void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
  175. {
  176. ai_assert(p_ppcOut != NULL);
  177. // read chunk
  178. if (this->mCurrent >= this->mLast)
  179. {
  180. throw new ImportErrorException("Unexpected end of file, can't read chunk header");
  181. }
  182. const uintptr_t iDiff = this->mLast - this->mCurrent;
  183. if (iDiff < sizeof(Dot3DSFile::Chunk))
  184. {
  185. *p_ppcOut = NULL;
  186. return;
  187. }
  188. *p_ppcOut = (const Dot3DSFile::Chunk*) this->mCurrent;
  189. if ((**p_ppcOut).Size + this->mCurrent > this->mLast)
  190. {
  191. throw new ImportErrorException("Unexpected end of file, can't read chunk footer");
  192. }
  193. this->mCurrent += sizeof(Dot3DSFile::Chunk);
  194. return;
  195. }
  196. // ------------------------------------------------------------------------------------------------
  197. void Dot3DSImporter::ParseMainChunk(int& piRemaining)
  198. {
  199. const Dot3DSFile::Chunk* psChunk;
  200. this->ReadChunk(&psChunk);
  201. const unsigned char* pcCur = this->mCurrent;
  202. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  203. - sizeof(Dot3DSFile::Chunk));
  204. // get chunk type
  205. int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  206. switch (psChunk->Flag)
  207. {
  208. case Dot3DSFile::CHUNK_MAIN:
  209. //case 0x444d: // bugfix
  210. this->ParseEditorChunk(iRemaining);
  211. break;
  212. };
  213. if (pcCurNext < this->mCurrent)
  214. {
  215. // place an error message. If we crash the programmer
  216. // will be able to find it
  217. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  218. pcCurNext = this->mCurrent;
  219. }
  220. // Go to the starting position of the next top-level chunk
  221. this->mCurrent = pcCurNext;
  222. piRemaining -= psChunk->Size;
  223. if (0 >= piRemaining)return;
  224. return this->ParseMainChunk(piRemaining);
  225. }
  226. // ------------------------------------------------------------------------------------------------
  227. void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
  228. {
  229. const Dot3DSFile::Chunk* psChunk;
  230. this->ReadChunk(&psChunk);
  231. const unsigned char* pcCur = this->mCurrent;
  232. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  233. - sizeof(Dot3DSFile::Chunk));
  234. // get chunk type
  235. int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  236. switch (psChunk->Flag)
  237. {
  238. case Dot3DSFile::CHUNK_OBJMESH:
  239. this->ParseObjectChunk(iRemaining);
  240. break;
  241. // NOTE: In several documentations in the internet this
  242. // chunk appears at different locations
  243. case Dot3DSFile::CHUNK_KEYFRAMER:
  244. this->ParseKeyframeChunk(iRemaining);
  245. break;
  246. case Dot3DSFile::CHUNK_VERSION:
  247. if (psChunk->Size >= 2+sizeof(Dot3DSFile::Chunk))
  248. {
  249. // print the version number
  250. char szBuffer[128];
  251. #if _MSC_VER >= 1400
  252. ::sprintf_s(szBuffer,"3DS file version chunk: %i",
  253. (int) *((uint16_t*)this->mCurrent));
  254. #else
  255. ::sprintf(szBuffer,"3DS file version chunk: %i",
  256. (int) *((uint16_t*)this->mCurrent));
  257. #endif
  258. DefaultLogger::get()->info(szBuffer);
  259. }
  260. else
  261. {
  262. DefaultLogger::get()->warn("Invalid version chunk in 3DS file");
  263. }
  264. break;
  265. };
  266. if (pcCurNext < this->mCurrent)
  267. {
  268. // place an error message. If we crash the programmer
  269. // will be able to find it
  270. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  271. pcCurNext = this->mCurrent;
  272. }
  273. // Go to the starting position of the next top-level chunk
  274. this->mCurrent = pcCurNext;
  275. piRemaining -= psChunk->Size;
  276. if (0 >= piRemaining)return;
  277. return this->ParseEditorChunk(piRemaining);
  278. }
  279. // ------------------------------------------------------------------------------------------------
  280. void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
  281. {
  282. const Dot3DSFile::Chunk* psChunk;
  283. this->ReadChunk(&psChunk);
  284. const unsigned char* pcCur = this->mCurrent;
  285. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  286. - sizeof(Dot3DSFile::Chunk));
  287. const unsigned char* sz = this->mCurrent;
  288. unsigned int iCnt = 0;
  289. // get chunk type
  290. int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  291. switch (psChunk->Flag)
  292. {
  293. case Dot3DSFile::CHUNK_OBJBLOCK:
  294. this->mScene->mMeshes.push_back(Dot3DS::Mesh());
  295. // at first we need to parse the name of the
  296. // geometry object
  297. while (*sz++ != '\0')
  298. {
  299. if (sz > pcCurNext-1)break;
  300. ++iCnt;
  301. }
  302. this->mScene->mMeshes.back().mName = std::string(
  303. (const char*)this->mCurrent,iCnt);
  304. ++iCnt;
  305. this->mCurrent += iCnt;
  306. iRemaining -= iCnt;
  307. this->ParseChunk(iRemaining);
  308. break;
  309. case Dot3DSFile::CHUNK_MAT_MATERIAL:
  310. this->mScene->mMaterials.push_back(Dot3DS::Material());
  311. this->ParseMaterialChunk(iRemaining);
  312. break;
  313. case Dot3DSFile::CHUNK_AMBCOLOR:
  314. // This is the ambient base color of the scene.
  315. // We add it to the ambient color of all materials
  316. this->ParseColorChunk(&this->mClrAmbient,true);
  317. if (is_qnan(this->mClrAmbient.r))
  318. {
  319. this->mClrAmbient.r = 0.0f;
  320. this->mClrAmbient.g = 0.0f;
  321. this->mClrAmbient.b = 0.0f;
  322. }
  323. break;
  324. case Dot3DSFile::CHUNK_BIT_MAP:
  325. this->mBackgroundImage = std::string((const char*)this->mCurrent);
  326. break;
  327. case Dot3DSFile::CHUNK_BIT_MAP_EXISTS:
  328. bHasBG = true;
  329. break;
  330. case Dot3DSFile::CHUNK_MASTER_SCALE:
  331. this->mMasterScale = *((float*)this->mCurrent);
  332. this->mCurrent += sizeof(float);
  333. break;
  334. // NOTE: In several documentations in the internet this
  335. // chunk appears at different locations
  336. case Dot3DSFile::CHUNK_KEYFRAMER:
  337. this->ParseKeyframeChunk(iRemaining);
  338. break;
  339. };
  340. if (pcCurNext < this->mCurrent)
  341. {
  342. // place an error message. If we crash the programmer
  343. // will be able to find it
  344. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  345. pcCurNext = this->mCurrent;
  346. }
  347. // Go to the starting position of the next top-level chunk
  348. this->mCurrent = pcCurNext;
  349. piRemaining -= psChunk->Size;
  350. if (0 >= piRemaining)return;
  351. return this->ParseObjectChunk(piRemaining);
  352. }
  353. // ------------------------------------------------------------------------------------------------
  354. void Dot3DSImporter::SkipChunk()
  355. {
  356. const Dot3DSFile::Chunk* psChunk;
  357. this->ReadChunk(&psChunk);
  358. this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
  359. return;
  360. }
  361. // ------------------------------------------------------------------------------------------------
  362. void Dot3DSImporter::ParseChunk(int& piRemaining)
  363. {
  364. const Dot3DSFile::Chunk* psChunk;
  365. this->ReadChunk(&psChunk);
  366. const unsigned char* pcCur = this->mCurrent;
  367. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  368. - sizeof(Dot3DSFile::Chunk));
  369. // get chunk type
  370. int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  371. switch (psChunk->Flag)
  372. {
  373. case Dot3DSFile::CHUNK_TRIMESH:
  374. // this starts a new mesh
  375. this->ParseMeshChunk(iRemaining);
  376. break;
  377. };
  378. if (pcCurNext < this->mCurrent)
  379. {
  380. // place an error message. If we crash the programmer
  381. // will be able to find it
  382. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  383. pcCurNext = this->mCurrent;
  384. }
  385. // Go to the starting position of the next top-level chunk
  386. this->mCurrent = pcCurNext;
  387. piRemaining -= psChunk->Size;
  388. if (0 >= piRemaining)return;
  389. return this->ParseChunk(piRemaining);
  390. }
  391. // ------------------------------------------------------------------------------------------------
  392. void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
  393. {
  394. const Dot3DSFile::Chunk* psChunk;
  395. this->ReadChunk(&psChunk);
  396. const unsigned char* pcCur = this->mCurrent;
  397. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  398. - sizeof(Dot3DSFile::Chunk));
  399. // get chunk type
  400. int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  401. switch (psChunk->Flag)
  402. {
  403. case Dot3DSFile::CHUNK_TRACKINFO:
  404. // this starts a new mesh
  405. this->ParseHierarchyChunk(iRemaining);
  406. break;
  407. };
  408. if (pcCurNext < this->mCurrent)
  409. {
  410. // place an error message. If we crash the programmer
  411. // will be able to find it
  412. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  413. pcCurNext = this->mCurrent;
  414. }
  415. // Go to the starting position of the next top-level chunk
  416. this->mCurrent = pcCurNext;
  417. piRemaining -= psChunk->Size;
  418. if (0 >= piRemaining)return;
  419. return this->ParseKeyframeChunk(piRemaining);
  420. }
  421. // ------------------------------------------------------------------------------------------------
  422. void Dot3DSImporter::InverseNodeSearch(Dot3DS::Node* pcNode,Dot3DS::Node* pcCurrent)
  423. {
  424. if (NULL == pcCurrent)
  425. {
  426. this->mRootNode->push_back(pcNode);
  427. return;
  428. }
  429. if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos)
  430. {
  431. if(NULL != pcCurrent->mParent)
  432. pcCurrent->mParent->push_back(pcNode);
  433. else pcCurrent->push_back(pcNode);
  434. return;
  435. }
  436. return this->InverseNodeSearch(pcNode,pcCurrent->mParent);
  437. }
  438. // ------------------------------------------------------------------------------------------------
  439. void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
  440. {
  441. const Dot3DSFile::Chunk* psChunk;
  442. this->ReadChunk(&psChunk);
  443. const unsigned char* pcCur = this->mCurrent;
  444. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  445. - sizeof(Dot3DSFile::Chunk));
  446. // get chunk type
  447. const unsigned char* sz = (unsigned char*)this->mCurrent;
  448. unsigned int iCnt = 0;
  449. uint16_t iHierarchy;
  450. // uint16_t iTemp;
  451. Dot3DS::Node* pcNode;
  452. switch (psChunk->Flag)
  453. {
  454. case Dot3DSFile::CHUNK_TRACKOBJNAME:
  455. // get object name
  456. while (*sz++ != '\0')
  457. {
  458. if (sz > pcCurNext-1)break;
  459. ++iCnt;
  460. }
  461. pcNode = new Dot3DS::Node();
  462. pcNode->mName = std::string((const char*)this->mCurrent,iCnt);
  463. iCnt++;
  464. // there are two unknown values which we can safely ignore
  465. this->mCurrent += iCnt + sizeof(uint16_t)*2;
  466. iHierarchy = *((uint16_t*)this->mCurrent);
  467. iHierarchy++;
  468. pcNode->mHierarchyPos = iHierarchy;
  469. pcNode->mHierarchyIndex = this->mLastNodeIndex;
  470. if (this->mCurrentNode && this->mCurrentNode->mHierarchyPos == iHierarchy)
  471. {
  472. // add to the parent of the last touched node
  473. this->mCurrentNode->mParent->push_back(pcNode);
  474. this->mLastNodeIndex++;
  475. }
  476. else if(iHierarchy >= this->mLastNodeIndex)
  477. {
  478. // place it at the current position in the hierarchy
  479. this->mCurrentNode->push_back(pcNode);
  480. this->mLastNodeIndex = iHierarchy;
  481. }
  482. else
  483. {
  484. // need to go back to the specified position in the hierarchy.
  485. this->InverseNodeSearch(pcNode,this->mCurrentNode);
  486. this->mLastNodeIndex++;
  487. }
  488. this->mCurrentNode = pcNode;
  489. break;
  490. case Dot3DSFile::CHUNK_TRACKPIVOT:
  491. // pivot = origin of rotation and scaling
  492. this->mCurrentNode->vPivot = *((const aiVector3D*)this->mCurrent);
  493. this->mCurrent += sizeof(aiVector3D);
  494. break;
  495. #ifdef AI_3DS_KEYFRAME_ANIMATION
  496. case Dot3DSFile::CHUNK_TRACKPOS:
  497. /*
  498. +2 short flags;
  499. +8 short unknown[4];
  500. +2 short keys;
  501. +2 short unknown;
  502. struct {
  503. +2 short framenum;
  504. +4 long unknown;
  505. float pos_x, pos_y, pos_z;
  506. } pos[keys];
  507. */
  508. this->mCurrent += 10;
  509. iTemp = *((const uint16_t*)mCurrent);
  510. this->mCurrent += sizeof(uint16_t) * 2;
  511. for (unsigned int i = 0; i < (unsigned int)iTemp;++i)
  512. {
  513. uint16_t sNum = *((const uint16_t*)mCurrent);
  514. this->mCurrent += sizeof(uint16_t);
  515. aiVectorKey v;
  516. v.mTime = (double)sNum;
  517. this->mCurrent += sizeof(uint32_t);
  518. v.mValue = *((const aiVector3D*)this->mCurrent);
  519. this->mCurrent += sizeof(aiVector3D);
  520. // check whether we do already have this keyframe
  521. for (std::vector<aiVectorKey>::const_iterator
  522. i = this->mCurrentNode->aPositionKeys.begin();
  523. i != this->mCurrentNode->aPositionKeys.end();++i)
  524. {
  525. if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
  526. }
  527. // add the new keyframe
  528. if (v.mTime != -10e10f)this->mCurrentNode->aPositionKeys.push_back(v);
  529. }
  530. break;
  531. case Dot3DSFile::CHUNK_TRACKROTATE:
  532. /*
  533. +2 short flags;
  534. +8 short unknown[4];
  535. +2 short keys;
  536. +2 short unknown;
  537. struct {
  538. +2 short framenum;
  539. +4 long unknown;
  540. float rad , pos_x, pos_y, pos_z;
  541. } pos[keys];
  542. */
  543. this->mCurrent += 10;
  544. iTemp = *((const uint16_t*)mCurrent);
  545. this->mCurrent += sizeof(uint16_t) * 2;
  546. for (unsigned int i = 0; i < (unsigned int)iTemp;++i)
  547. {
  548. uint16_t sNum = *((const uint16_t*)mCurrent);
  549. this->mCurrent += sizeof(uint16_t);
  550. aiQuatKey v;
  551. v.mTime = (double)sNum;
  552. this->mCurrent += sizeof(uint32_t);
  553. float fRadians = *((const float*)this->mCurrent);
  554. this->mCurrent += sizeof(float);
  555. aiVector3D vAxis = *((const aiVector3D*)this->mCurrent);
  556. this->mCurrent += sizeof(aiVector3D);
  557. // construct a rotation quaternion from the axis-angle pair
  558. v.mValue = aiQuaternion(vAxis,fRadians);
  559. // check whether we do already have this keyframe
  560. for (std::vector<aiQuatKey>::const_iterator
  561. i = this->mCurrentNode->aRotationKeys.begin();
  562. i != this->mCurrentNode->aRotationKeys.end();++i)
  563. {
  564. if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
  565. }
  566. // add the new keyframe
  567. if (v.mTime != -10e10f)this->mCurrentNode->aRotationKeys.push_back(v);
  568. }
  569. break;
  570. case Dot3DSFile::CHUNK_TRACKSCALE:
  571. /*
  572. +2 short flags;
  573. +8 short unknown[4];
  574. +2 short keys;
  575. +2 short unknown;
  576. struct {
  577. +2 short framenum;
  578. +4 long unknown;
  579. float pos_x, pos_y, pos_z;
  580. } pos[keys];
  581. */
  582. this->mCurrent += 10;
  583. iTemp = *((const uint16_t*)mCurrent);
  584. this->mCurrent += sizeof(uint16_t) * 2;
  585. for (unsigned int i = 0; i < (unsigned int)iTemp;++i)
  586. {
  587. uint16_t sNum = *((const uint16_t*)mCurrent);
  588. this->mCurrent += sizeof(uint16_t);
  589. aiVectorKey v;
  590. v.mTime = (double)sNum;
  591. this->mCurrent += sizeof(uint32_t);
  592. v.mValue = *((const aiVector3D*)this->mCurrent);
  593. this->mCurrent += sizeof(aiVector3D);
  594. // check whether we do already have this keyframe
  595. for (std::vector<aiVectorKey>::const_iterator
  596. i = this->mCurrentNode->aScalingKeys.begin();
  597. i != this->mCurrentNode->aScalingKeys.end();++i)
  598. {
  599. if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
  600. }
  601. // add the new keyframe
  602. if (v.mTime != -10e10f)this->mCurrentNode->aScalingKeys.push_back(v);
  603. if (v.mValue.x && v.mValue.y && v.mValue.z)
  604. {
  605. DefaultLogger::get()->warn("Found zero scaled axis in scaling keyframe");
  606. ++iCnt;
  607. }
  608. }
  609. // there are 3DS files that have only zero scalings
  610. if (iTemp == iCnt)
  611. {
  612. DefaultLogger::get()->warn("All scaling keys are zero. They will be removed");
  613. this->mCurrentNode->aScalingKeys.clear();
  614. }
  615. break;
  616. #endif
  617. };
  618. if (pcCurNext < this->mCurrent)
  619. {
  620. // place an error message. If we crash the programmer
  621. // will be able to find it
  622. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  623. pcCurNext = this->mCurrent;
  624. }
  625. // Go to the starting position of the next top-level chunk
  626. this->mCurrent = pcCurNext;
  627. piRemaining -= psChunk->Size;
  628. if (0 >= piRemaining)return;
  629. return this->ParseHierarchyChunk(piRemaining);
  630. }
  631. // ------------------------------------------------------------------------------------------------
  632. void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
  633. {
  634. const Dot3DSFile::Chunk* psChunk;
  635. Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
  636. this->ReadChunk(&psChunk);
  637. const unsigned char* pcCur = this->mCurrent;
  638. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  639. - sizeof(Dot3DSFile::Chunk));
  640. // get chunk type
  641. const unsigned char* sz = this->mCurrent;
  642. uint32_t iCnt = 0,iTemp;
  643. switch (psChunk->Flag)
  644. {
  645. case Dot3DSFile::CHUNK_SMOOLIST:
  646. // one int32 for each face
  647. for (std::vector<Dot3DS::Face>::iterator
  648. i = mMesh.mFaces.begin();
  649. i != mMesh.mFaces.end();++i)
  650. {
  651. // nth bit is set for nth smoothing group
  652. (*i).iSmoothGroup = *((uint32_t*)this->mCurrent);
  653. this->mCurrent += sizeof(uint32_t);
  654. }
  655. break;
  656. case Dot3DSFile::CHUNK_FACEMAT:
  657. // at fist an asciiz with the material name
  658. while (*sz++)
  659. {
  660. // make sure we don't run over the end of the chunk
  661. if (sz > pcCurNext-1)break;
  662. }
  663. // find the index of the material
  664. unsigned int iIndex = 0xFFFFFFFF;
  665. iCnt = 0;
  666. for (std::vector<Dot3DS::Material>::const_iterator
  667. i = this->mScene->mMaterials.begin();
  668. i != this->mScene->mMaterials.end();++i,++iCnt)
  669. {
  670. // compare case-independent to be sure it works
  671. if (0 == ASSIMP_stricmp((const char*)this->mCurrent,
  672. (const char*)((*i).mName.c_str())))
  673. {
  674. iIndex = iCnt;
  675. break;
  676. }
  677. }
  678. if (0xFFFFFFFF == iIndex)
  679. {
  680. // this material is not known. Ignore this. We will later
  681. // assign the default material to all faces using *this*
  682. // material. Use 0xcdcdcdcd as special value to indicate
  683. // this.
  684. iIndex = 0xcdcdcdcd;
  685. }
  686. this->mCurrent = sz;
  687. iCnt = (int)(*((uint16_t*)this->mCurrent));
  688. this->mCurrent += sizeof(uint16_t);
  689. for (unsigned int i = 0; i < iCnt;++i)
  690. {
  691. iTemp = (uint16_t)*((uint16_t*)this->mCurrent);
  692. // check range
  693. if (iTemp >= mMesh.mFaceMaterials.size())
  694. {
  695. DefaultLogger::get()->error("Invalid face index in face material list");
  696. mMesh.mFaceMaterials[mMesh.mFaceMaterials.size()-1] = iIndex;
  697. }
  698. else
  699. {
  700. mMesh.mFaceMaterials[iTemp] = iIndex;
  701. }
  702. this->mCurrent += sizeof(uint16_t);
  703. }
  704. break;
  705. };
  706. if (pcCurNext < this->mCurrent)
  707. {
  708. // place an error message. If we crash the programmer
  709. // will be able to find it
  710. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  711. pcCurNext = this->mCurrent;
  712. }
  713. // Go to the starting position of the next chunk on this level
  714. this->mCurrent = pcCurNext;
  715. piRemaining -= psChunk->Size;
  716. if (0 >= piRemaining)return;
  717. return ParseFaceChunk(piRemaining);
  718. }
  719. // ------------------------------------------------------------------------------------------------
  720. void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
  721. {
  722. const Dot3DSFile::Chunk* psChunk;
  723. Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
  724. this->ReadChunk(&psChunk);
  725. const unsigned char* pcCur = this->mCurrent;
  726. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  727. - sizeof(Dot3DSFile::Chunk));
  728. // get chunk type
  729. const unsigned char* sz = this->mCurrent;
  730. unsigned int iCnt = 0;
  731. int iRemaining;
  732. uint16_t iNum = 0;
  733. float* pf;
  734. switch (psChunk->Flag)
  735. {
  736. case Dot3DSFile::CHUNK_VERTLIST:
  737. iNum = *((short*)this->mCurrent);
  738. this->mCurrent += sizeof(short);
  739. while (iNum-- > 0)
  740. {
  741. mMesh.mPositions.push_back(*((aiVector3D*)this->mCurrent));
  742. aiVector3D& v = mMesh.mPositions.back();
  743. //std::swap( v.y, v.z);
  744. //v.y *= -1.0f;
  745. this->mCurrent += sizeof(aiVector3D);
  746. }
  747. break;
  748. case Dot3DSFile::CHUNK_TRMATRIX:
  749. {
  750. // http://www.gamedev.net/community/forums/topic.asp?topic_id=263063
  751. // http://www.gamedev.net/community/forums/topic.asp?topic_id=392310
  752. pf = (float*)this->mCurrent;
  753. this->mCurrent += 12 * sizeof(float);
  754. mMesh.mMat.a1 = pf[0];
  755. mMesh.mMat.b1 = pf[1];
  756. mMesh.mMat.c1 = pf[2];
  757. mMesh.mMat.a2 = pf[3];
  758. mMesh.mMat.b2 = pf[4];
  759. mMesh.mMat.c2 = pf[5];
  760. mMesh.mMat.a3 = pf[6];
  761. mMesh.mMat.b3 = pf[7];
  762. mMesh.mMat.c3 = pf[8];
  763. mMesh.mMat.a4 = pf[9];
  764. mMesh.mMat.b4 = pf[10];
  765. mMesh.mMat.c4 = pf[11];
  766. //mMesh.mMat.Transpose(); // todo ----
  767. // now check whether the matrix has got a negative determinant
  768. // If yes, we need to flip all vertices' x axis ....
  769. // From lib3ds, mesh.c
  770. if (mMesh.mMat.Determinant() < 0.0f)
  771. {
  772. aiMatrix4x4 mInv = mMesh.mMat;
  773. mInv.Inverse();
  774. aiMatrix4x4 mMe = mMesh.mMat;
  775. mMe.a1 *= -1.0f;
  776. mMe.b1 *= -1.0f;
  777. mMe.c1 *= -1.0f;
  778. mMe.d1 *= -1.0f;
  779. mInv = mInv * mMe;
  780. for (register unsigned int i = 0; i < mMesh.mPositions.size();++i)
  781. {
  782. aiVector3D a,c;
  783. a = mMesh.mPositions[i];
  784. c[0]= mInv[0][0]*a[0] + mInv[1][0]*a[1] + mInv[2][0]*a[2] + mInv[3][0];
  785. c[1]= mInv[0][1]*a[0] + mInv[1][1]*a[1] + mInv[2][1]*a[2] + mInv[3][1];
  786. c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2];
  787. mMesh.mPositions[i] = c;
  788. }
  789. }
  790. }
  791. break;
  792. case Dot3DSFile::CHUNK_MAPLIST:
  793. iNum = *((uint16_t*)this->mCurrent);
  794. this->mCurrent += sizeof(uint16_t);
  795. while (iNum-- > 0)
  796. {
  797. mMesh.mTexCoords.push_back(*((aiVector2D*)this->mCurrent));
  798. this->mCurrent += sizeof(aiVector2D);
  799. }
  800. break;
  801. #if 0
  802. case Dot3DSFile::CHUNK_TXTINFO:
  803. // for debugging purposes. Read two bytes to determine the mapping type
  804. iNum = *((uint16_t*)this->mCurrent);
  805. this->mCurrent += sizeof(uint16_t);
  806. break;
  807. #endif
  808. case Dot3DSFile::CHUNK_FACELIST:
  809. iNum = *((uint16_t*)this->mCurrent);
  810. this->mCurrent += sizeof(uint16_t);
  811. while (iNum-- > 0)
  812. {
  813. Dot3DS::Face sFace;
  814. sFace.mIndices[0] = *((uint16_t*)this->mCurrent);
  815. this->mCurrent += sizeof(uint16_t);
  816. sFace.mIndices[1] = *((uint16_t*)this->mCurrent);
  817. this->mCurrent += sizeof(uint16_t);
  818. sFace.mIndices[2] = *((uint16_t*)this->mCurrent);
  819. this->mCurrent += 2*sizeof(uint16_t);
  820. mMesh.mFaces.push_back(sFace);
  821. }
  822. // resize the material array (0xcdcdcdcd marks the
  823. // default material; so if a face is not referenced
  824. // by a material $$DEFAULT will be assigned to it)
  825. mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd);
  826. iRemaining = (int)(pcCurNext - this->mCurrent);
  827. if (iRemaining > 0)this->ParseFaceChunk(iRemaining);
  828. break;
  829. };
  830. if (pcCurNext < this->mCurrent)
  831. {
  832. // place an error message. If we crash the programmer
  833. // will be able to find it
  834. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  835. pcCurNext = this->mCurrent;
  836. }
  837. // Go to the starting position of the next chunk on this level
  838. this->mCurrent = pcCurNext;
  839. piRemaining -= psChunk->Size;
  840. if (0 >= piRemaining)return;
  841. return ParseMeshChunk(piRemaining);
  842. }
  843. // ------------------------------------------------------------------------------------------------
  844. void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
  845. {
  846. const Dot3DSFile::Chunk* psChunk;
  847. this->ReadChunk(&psChunk);
  848. const unsigned char* pcCur = this->mCurrent;
  849. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  850. - sizeof(Dot3DSFile::Chunk));
  851. // get chunk type
  852. const unsigned char* sz = this->mCurrent;
  853. unsigned int iCnt = 0;
  854. int iRemaining;
  855. aiColor3D* pc;
  856. float* pcf;
  857. switch (psChunk->Flag)
  858. {
  859. case Dot3DSFile::CHUNK_MAT_MATNAME:
  860. // string in file is zero-terminated,
  861. // this should be no problem. However, validate whether
  862. // it overlaps the end of the chunk, if yes we should
  863. // truncate it.
  864. while (*sz++ != '\0')
  865. {
  866. if (sz > pcCurNext-1)break;
  867. ++iCnt;
  868. }
  869. this->mScene->mMaterials.back().mName = std::string(
  870. (const char*)this->mCurrent,iCnt);
  871. break;
  872. case Dot3DSFile::CHUNK_MAT_DIFFUSE:
  873. pc = &this->mScene->mMaterials.back().mDiffuse;
  874. this->ParseColorChunk(pc);
  875. if (is_qnan(pc->r))
  876. {
  877. // color chunk is invalid. Simply ignore it
  878. pc->r = pc->g = pc->b = 1.0f;
  879. }
  880. break;
  881. case Dot3DSFile::CHUNK_MAT_SPECULAR:
  882. pc = &this->mScene->mMaterials.back().mSpecular;
  883. this->ParseColorChunk(pc);
  884. if (is_qnan(pc->r))
  885. {
  886. // color chunk is invalid. Simply ignore it
  887. pc->r = pc->g = pc->b = 1.0f;
  888. }
  889. break;
  890. case Dot3DSFile::CHUNK_MAT_AMBIENT:
  891. pc = &this->mScene->mMaterials.back().mAmbient;
  892. this->ParseColorChunk(pc);
  893. if (is_qnan(pc->r))
  894. {
  895. // color chunk is invalid. Simply ignore it
  896. pc->r = pc->g = pc->b = 1.0f;
  897. }
  898. break;
  899. case Dot3DSFile::CHUNK_MAT_SELF_ILLUM:
  900. pc = &this->mScene->mMaterials.back().mEmissive;
  901. this->ParseColorChunk(pc);
  902. if (is_qnan(pc->r))
  903. {
  904. // color chunk is invalid. Simply ignore it
  905. // EMISSSIVE TO 0|0|0
  906. pc->r = pc->g = pc->b = 0.0f;
  907. }
  908. break;
  909. case Dot3DSFile::CHUNK_MAT_TRANSPARENCY:
  910. pcf = &this->mScene->mMaterials.back().mTransparency;
  911. *pcf = this->ParsePercentageChunk();
  912. // NOTE: transparency, not opacity
  913. if (is_qnan(*pcf))
  914. *pcf = 1.0f;
  915. else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
  916. break;
  917. case Dot3DSFile::CHUNK_MAT_SHADING:
  918. this->mScene->mMaterials.back().mShading =
  919. (Dot3DS::Dot3DSFile::shadetype3ds)*((uint16_t*)this->mCurrent);
  920. this->mCurrent += sizeof(uint16_t);
  921. break;
  922. case Dot3DSFile::CHUNK_MAT_TWO_SIDE:
  923. this->mScene->mMaterials.back().mTwoSided = true;
  924. break;
  925. case Dot3DSFile::CHUNK_MAT_SHININESS:
  926. pcf = &this->mScene->mMaterials.back().mSpecularExponent;
  927. *pcf = this->ParsePercentageChunk();
  928. if (is_qnan(*pcf))
  929. *pcf = 0.0f;
  930. else *pcf *= (float)0xFFFF;
  931. break;
  932. case Dot3DSFile::CHUNK_MAT_SHININESS_PERCENT:
  933. pcf = &this->mScene->mMaterials.back().mShininessStrength;
  934. *pcf = this->ParsePercentageChunk();
  935. if (is_qnan(*pcf))
  936. *pcf = 0.0f;
  937. else *pcf *= (float)0xffff / 100.0f;
  938. break;
  939. case Dot3DSFile::CHUNK_MAT_SELF_ILPCT:
  940. // TODO: need to multiply with emissive base color?
  941. pcf = &this->mScene->mMaterials.back().sTexEmissive.mTextureBlend;
  942. *pcf = this->ParsePercentageChunk();
  943. if (is_qnan(*pcf))
  944. *pcf = 0.0f;
  945. else *pcf = *pcf * (float)0xFFFF / 100.0f;
  946. break;
  947. // parse texture chunks
  948. case Dot3DSFile::CHUNK_MAT_TEXTURE:
  949. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  950. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexDiffuse);
  951. break;
  952. case Dot3DSFile::CHUNK_MAT_BUMPMAP:
  953. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  954. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexBump);
  955. break;
  956. case Dot3DSFile::CHUNK_MAT_OPACMAP:
  957. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  958. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexOpacity);
  959. break;
  960. case Dot3DSFile::CHUNK_MAT_MAT_SHINMAP:
  961. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  962. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexShininess);
  963. break;
  964. case Dot3DSFile::CHUNK_MAT_SPECMAP:
  965. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  966. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexSpecular);
  967. break;
  968. case Dot3DSFile::CHUNK_MAT_SELFIMAP:
  969. iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
  970. this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexEmissive);
  971. break;
  972. };
  973. if (pcCurNext < this->mCurrent)
  974. {
  975. // place an error message. If we crash the programmer
  976. // will be able to find it
  977. DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
  978. pcCurNext = this->mCurrent;
  979. }
  980. // Go to the starting position of the next chunk on this level
  981. this->mCurrent = pcCurNext;
  982. piRemaining -= psChunk->Size;
  983. if (0 >= piRemaining)return;
  984. return ParseMaterialChunk(piRemaining);
  985. }
  986. // ------------------------------------------------------------------------------------------------
  987. void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
  988. {
  989. const Dot3DSFile::Chunk* psChunk;
  990. this->ReadChunk(&psChunk);
  991. const unsigned char* pcCur = this->mCurrent;
  992. const unsigned char* pcCurNext = pcCur + (psChunk->Size
  993. - sizeof(Dot3DSFile::Chunk));
  994. // get chunk type
  995. const unsigned char* sz = this->mCurrent;
  996. unsigned int iCnt = 0;
  997. switch (psChunk->Flag)
  998. {
  999. case Dot3DSFile::CHUNK_MAPFILE:
  1000. // string in file is zero-terminated,
  1001. // this should be no problem. However, validate whether
  1002. // it overlaps the end of the chunk, if yes we should
  1003. // truncate it.
  1004. while (*sz++ != '\0')
  1005. {
  1006. if (sz > pcCurNext-1)break;
  1007. ++iCnt;
  1008. }
  1009. pcOut->mMapName = std::string((const char*)this->mCurrent,iCnt);
  1010. break;
  1011. // manually parse the blend factor
  1012. case Dot3DSFile::CHUNK_PERCENTF:
  1013. pcOut->mTextureBlend = *((float*)this->mCurrent);
  1014. break;
  1015. // manually parse the blend factor
  1016. case Dot3DSFile::CHUNK_PERCENTW:
  1017. pcOut->mTextureBlend = (float)(*((short*)this->mCurrent)) / 100.0f;
  1018. break;
  1019. case Dot3DSFile::CHUNK_MAT_MAP_USCALE:
  1020. pcOut->mScaleU = *((float*)this->mCurrent);
  1021. if (0.0f == pcOut->mScaleU)
  1022. {
  1023. DefaultLogger::get()->warn("Texture coordinate scaling in the "
  1024. "x direction is zero. Assuming this should be 1.0 ... ");
  1025. pcOut->mScaleU = 1.0f;
  1026. }
  1027. // NOTE: some docs state it is 1/u, others say it is u ... ARGHH!
  1028. //pcOut->mScaleU = 1.0f / pcOut->mScaleU;
  1029. break;
  1030. case Dot3DSFile::CHUNK_MAT_MAP_VSCALE:
  1031. pcOut->mScaleV = *((float*)this->mCurrent);
  1032. if (0.0f == pcOut->mScaleV)
  1033. {
  1034. DefaultLogger::get()->warn("Texture coordinate scaling in the "
  1035. "y direction is zero. Assuming this should be 1.0 ... ");
  1036. pcOut->mScaleV = 1.0f;
  1037. }
  1038. // NOTE: some docs state it is 1/v, others say it is v ... ARGHH!
  1039. //pcOut->mScaleV = 1.0f / pcOut->mScaleV;
  1040. break;
  1041. case Dot3DSFile::CHUNK_MAT_MAP_UOFFSET:
  1042. pcOut->mOffsetU = *((float*)this->mCurrent);
  1043. break;
  1044. case Dot3DSFile::CHUNK_MAT_MAP_VOFFSET:
  1045. pcOut->mOffsetV = *((float*)this->mCurrent);
  1046. break;
  1047. case Dot3DSFile::CHUNK_MAT_MAP_ANG:
  1048. pcOut->mRotation = *((float*)this->mCurrent);
  1049. break;
  1050. case Dot3DSFile::CHUNK_MAT_MAP_TILING:
  1051. uint16_t iFlags = *((uint16_t*)this->mCurrent);
  1052. // check whether the mirror flag is set
  1053. if (iFlags & 0x2u)
  1054. {
  1055. pcOut->mMapMode = aiTextureMapMode_Mirror;
  1056. }
  1057. // assume that "decal" means clamping ...
  1058. else if (iFlags & 0x10u && iFlags & 0x1u)
  1059. {
  1060. pcOut->mMapMode = aiTextureMapMode_Clamp;
  1061. }
  1062. break;
  1063. };
  1064. // Go to the starting position of the next chunk on this level
  1065. this->mCurrent = pcCurNext;
  1066. piRemaining -= psChunk->Size;
  1067. if (0 >= piRemaining)return;
  1068. return ParseTextureChunk(piRemaining,pcOut);
  1069. }
  1070. // ------------------------------------------------------------------------------------------------
  1071. float Dot3DSImporter::ParsePercentageChunk()
  1072. {
  1073. const Dot3DSFile::Chunk* psChunk;
  1074. this->ReadChunk(&psChunk);
  1075. if (NULL == psChunk)return std::numeric_limits<float>::quiet_NaN();
  1076. if (Dot3DSFile::CHUNK_PERCENTF == psChunk->Flag)
  1077. {
  1078. if (sizeof(float) > psChunk->Size)
  1079. return std::numeric_limits<float>::quiet_NaN();
  1080. return *((float*)this->mCurrent);
  1081. }
  1082. else if (Dot3DSFile::CHUNK_PERCENTW == psChunk->Flag)
  1083. {
  1084. if (2 > psChunk->Size)
  1085. return std::numeric_limits<float>::quiet_NaN();
  1086. return (float)(*((short*)this->mCurrent)) / (float)0xFFFF;
  1087. }
  1088. this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
  1089. return std::numeric_limits<float>::quiet_NaN();
  1090. }
  1091. // ------------------------------------------------------------------------------------------------
  1092. void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
  1093. bool p_bAcceptPercent)
  1094. {
  1095. ai_assert(p_pcOut != NULL);
  1096. // error return value
  1097. static const aiColor3D clrError = aiColor3D(std::numeric_limits<float>::quiet_NaN(),
  1098. std::numeric_limits<float>::quiet_NaN(),
  1099. std::numeric_limits<float>::quiet_NaN());
  1100. const Dot3DSFile::Chunk* psChunk;
  1101. this->ReadChunk(&psChunk);
  1102. if (NULL == psChunk)
  1103. {
  1104. *p_pcOut = clrError;
  1105. return;
  1106. }
  1107. const unsigned char* pcCur = this->mCurrent;
  1108. this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
  1109. bool bGamma = false;
  1110. switch(psChunk->Flag)
  1111. {
  1112. case Dot3DSFile::CHUNK_LINRGBF:
  1113. bGamma = true;
  1114. case Dot3DSFile::CHUNK_RGBF:
  1115. if (sizeof(float) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
  1116. {
  1117. *p_pcOut = clrError;
  1118. return;
  1119. }
  1120. p_pcOut->r = ((float*)pcCur)[0];
  1121. p_pcOut->g = ((float*)pcCur)[1];
  1122. p_pcOut->b = ((float*)pcCur)[2];
  1123. break;
  1124. case Dot3DSFile::CHUNK_LINRGBB:
  1125. bGamma = true;
  1126. case Dot3DSFile::CHUNK_RGBB:
  1127. if (sizeof(char) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
  1128. {
  1129. *p_pcOut = clrError;
  1130. return;
  1131. }
  1132. p_pcOut->r = (float)pcCur[0] / 255.0f;
  1133. p_pcOut->g = (float)pcCur[1] / 255.0f;
  1134. p_pcOut->b = (float)pcCur[2] / 255.0f;
  1135. break;
  1136. // percentage chunks: accepted to be compatible with various
  1137. // .3ds files with very curious content
  1138. case Dot3DSFile::CHUNK_PERCENTF:
  1139. if (p_bAcceptPercent && 4 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
  1140. {
  1141. p_pcOut->r = *((float*)pcCur);
  1142. p_pcOut->g = *((float*)pcCur);
  1143. p_pcOut->b = *((float*)pcCur);
  1144. break;
  1145. }
  1146. *p_pcOut = clrError;
  1147. return;
  1148. case Dot3DSFile::CHUNK_PERCENTW:
  1149. if (p_bAcceptPercent && 1 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
  1150. {
  1151. p_pcOut->r = (float)pcCur[0] / 255.0f;
  1152. p_pcOut->g = (float)pcCur[0] / 255.0f;
  1153. p_pcOut->b = (float)pcCur[0] / 255.0f;
  1154. break;
  1155. }
  1156. *p_pcOut = clrError;
  1157. return;
  1158. default:
  1159. // skip unknown chunks, hope this won't cause any problems.
  1160. return this->ParseColorChunk(p_pcOut,p_bAcceptPercent);
  1161. };
  1162. // assume input gamma = 1.0, output gamma = 2.2
  1163. // Not sure whether this is correct, too tired to
  1164. // think about it ;-)
  1165. if (bGamma)
  1166. {
  1167. p_pcOut->r = powf(p_pcOut->r, 1.0f / 2.2f);
  1168. p_pcOut->g = powf(p_pcOut->g, 1.0f / 2.2f);
  1169. p_pcOut->b = powf(p_pcOut->b, 1.0f / 2.2f);
  1170. }
  1171. return;
  1172. }