3DSLoader.cpp 40 KB

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