3DSLoader.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  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 "AssimpPCH.h"
  36. #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
  37. // internal headers
  38. #include "3DSLoader.h"
  39. using namespace Assimp;
  40. // ------------------------------------------------------------------------------------------------
  41. // Begins a new parsing block
  42. // - Reads the current chunk and validates it
  43. // - computes its length
  44. #define ASSIMP_3DS_BEGIN_CHUNK() \
  45. Discreet3DS::Chunk chunk; \
  46. ReadChunk(&chunk); \
  47. int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \
  48. const int oldReadLimit = stream->GetReadLimit(); \
  49. stream->SetReadLimit(stream->GetCurrentPos() + chunkSize);
  50. // ------------------------------------------------------------------------------------------------
  51. // End a parsing block
  52. // Must follow at the end of each parsing block, reset chunk end marker to previous value
  53. #define ASSIMP_3DS_END_CHUNK() \
  54. stream->SkipToReadLimit(); \
  55. stream->SetReadLimit(oldReadLimit); \
  56. if (stream->GetRemainingSizeToLimit() == 0) \
  57. return;
  58. // ------------------------------------------------------------------------------------------------
  59. // Constructor to be privately used by Importer
  60. Discreet3DSImporter::Discreet3DSImporter()
  61. {}
  62. // ------------------------------------------------------------------------------------------------
  63. // Destructor, private as well
  64. Discreet3DSImporter::~Discreet3DSImporter()
  65. {}
  66. // ------------------------------------------------------------------------------------------------
  67. // Returns whether the class can handle the format of the given file.
  68. bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
  69. {
  70. // simple check of file extension is enough for the moment
  71. std::string::size_type pos = pFile.find_last_of('.');
  72. // no file extension - can't read
  73. if( pos == std::string::npos)
  74. return false;
  75. std::string extension = pFile.substr( pos);
  76. for (std::string::iterator i = extension.begin(); i != extension.end();++i)
  77. *i = ::tolower(*i);
  78. return (extension == ".3ds");
  79. }
  80. // ------------------------------------------------------------------------------------------------
  81. // Setup configuration properties
  82. void Discreet3DSImporter::SetupProperties(const Importer* pImp)
  83. {
  84. // nothing to be done for the moment
  85. }
  86. // ------------------------------------------------------------------------------------------------
  87. // Imports the given file into the given scene structure.
  88. void Discreet3DSImporter::InternReadFile( const std::string& pFile,
  89. aiScene* pScene, IOSystem* pIOHandler)
  90. {
  91. StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
  92. this->stream = &stream;
  93. // We should have at least one chunk
  94. if (stream.GetRemainingSize() < 16)
  95. throw new ImportErrorException("3DS file is either empty or corrupt: " + pFile);
  96. // Allocate our temporary 3DS representation
  97. mScene = new D3DS::Scene();
  98. // Initialize members
  99. mLastNodeIndex = -1;
  100. mCurrentNode = new D3DS::Node();
  101. mRootNode = mCurrentNode;
  102. mRootNode->mHierarchyPos = -1;
  103. mRootNode->mHierarchyIndex = -1;
  104. mRootNode->mParent = NULL;
  105. mMasterScale = 1.0f;
  106. mBackgroundImage = "";
  107. bHasBG = false;
  108. // Parse the file
  109. ParseMainChunk();
  110. // Process all meshes in the file. First check whether all
  111. // face indices haev valid values. The generate our
  112. // internal verbose representation. Finally compute normal
  113. // vectors from the smoothing groups we read from the
  114. // file.
  115. for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(),
  116. end = mScene->mMeshes.end(); i != end;++i)
  117. {
  118. CheckIndices(*i);
  119. MakeUnique (*i);
  120. ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
  121. }
  122. // Replace all occurences of the default material with a
  123. // valid material. Generate it if no material containing
  124. // DEFAULT in its name has been found in the file
  125. ReplaceDefaultMaterial();
  126. // Convert the scene from our internal representation to an
  127. // aiScene object. This involves copying all meshes, lights
  128. // and cameras to the scene
  129. ConvertScene(pScene);
  130. // Generate the node graph for the scene. This is a little bit
  131. // tricky since we'll need to split some meshes into submeshes
  132. GenerateNodeGraph(pScene);
  133. // Now apply the master scaling factor to the scene
  134. ApplyMasterScale(pScene);
  135. // Delete our internal scene representation and the root
  136. // node, so the whole hierarchy will follow
  137. delete mRootNode;
  138. delete mScene;
  139. AI_DEBUG_INVALIDATE_PTR(mRootNode);
  140. AI_DEBUG_INVALIDATE_PTR(mScene);
  141. AI_DEBUG_INVALIDATE_PTR(this->stream);
  142. }
  143. // ------------------------------------------------------------------------------------------------
  144. // Applies a master-scaling factor to the imported scene
  145. void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
  146. {
  147. // There are some 3DS files with a zero scaling factor
  148. if (!mMasterScale)mMasterScale = 1.0f;
  149. else mMasterScale = 1.0f / mMasterScale;
  150. // Construct an uniform scaling matrix and multiply with it
  151. pScene->mRootNode->mTransformation *= aiMatrix4x4(
  152. mMasterScale,0.0f, 0.0f, 0.0f,
  153. 0.0f, mMasterScale,0.0f, 0.0f,
  154. 0.0f, 0.0f, mMasterScale,0.0f,
  155. 0.0f, 0.0f, 0.0f, 1.0f);
  156. // Check whether a scaling track is assigned to the root node.
  157. }
  158. // ------------------------------------------------------------------------------------------------
  159. // Reads a new chunk from the file
  160. void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
  161. {
  162. ai_assert(pcOut != NULL);
  163. pcOut->Flag = stream->GetI2();
  164. pcOut->Size = stream->GetI4();
  165. if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
  166. throw new ImportErrorException("Chunk is too large");
  167. if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit())
  168. DefaultLogger::get()->error("3DS: Chunk overflow");
  169. }
  170. // ------------------------------------------------------------------------------------------------
  171. // Skip a chunk
  172. void Discreet3DSImporter::SkipChunk()
  173. {
  174. Discreet3DS::Chunk psChunk;
  175. ReadChunk(&psChunk);
  176. stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk));
  177. return;
  178. }
  179. // ------------------------------------------------------------------------------------------------
  180. // Process the primary chunk of the file
  181. void Discreet3DSImporter::ParseMainChunk()
  182. {
  183. ASSIMP_3DS_BEGIN_CHUNK();
  184. // get chunk type
  185. switch (chunk.Flag)
  186. {
  187. case Discreet3DS::CHUNK_MAIN:
  188. ParseEditorChunk();
  189. break;
  190. };
  191. ASSIMP_3DS_END_CHUNK();
  192. // recursively continue processing this hierarchy level
  193. return ParseMainChunk();
  194. }
  195. // ------------------------------------------------------------------------------------------------
  196. void Discreet3DSImporter::ParseEditorChunk()
  197. {
  198. ASSIMP_3DS_BEGIN_CHUNK();
  199. // get chunk type
  200. switch (chunk.Flag)
  201. {
  202. case Discreet3DS::CHUNK_OBJMESH:
  203. ParseObjectChunk();
  204. break;
  205. // NOTE: In several documentations in the internet this
  206. // chunk appears at different locations
  207. case Discreet3DS::CHUNK_KEYFRAMER:
  208. ParseKeyframeChunk();
  209. break;
  210. case Discreet3DS::CHUNK_VERSION:
  211. {
  212. // print the version number
  213. char buff[10];
  214. ASSIMP_itoa10(buff,stream->GetI2());
  215. DefaultLogger::get()->info(std::string("3DS file format version: ") + buff);
  216. }
  217. break;
  218. };
  219. ASSIMP_3DS_END_CHUNK();
  220. // recursively continue processing this hierarchy level
  221. return ParseEditorChunk();
  222. }
  223. // ------------------------------------------------------------------------------------------------
  224. void Discreet3DSImporter::ParseObjectChunk()
  225. {
  226. ASSIMP_3DS_BEGIN_CHUNK();
  227. // get chunk type
  228. switch (chunk.Flag)
  229. {
  230. case Discreet3DS::CHUNK_OBJBLOCK:
  231. {
  232. unsigned int cnt = 0;
  233. const char* sz = (const char*)stream->GetPtr();
  234. // Get the name of the geometry object
  235. while (stream->GetI1())++cnt;
  236. ParseChunk(sz,cnt);
  237. }
  238. break;
  239. case Discreet3DS::CHUNK_MAT_MATERIAL:
  240. // Add a new material to the list
  241. mScene->mMaterials.push_back(D3DS::Material());
  242. ParseMaterialChunk();
  243. break;
  244. case Discreet3DS::CHUNK_AMBCOLOR:
  245. // This is the ambient base color of the scene.
  246. // We add it to the ambient color of all materials
  247. ParseColorChunk(&mClrAmbient,true);
  248. if (is_qnan(mClrAmbient.r))
  249. {
  250. // We failed to read the ambient base color.
  251. DefaultLogger::get()->error("3DS: Failed to read ambient base color");
  252. mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
  253. }
  254. break;
  255. case Discreet3DS::CHUNK_BIT_MAP:
  256. {
  257. // Specifies the background image. The string should already be
  258. // properly 0 terminated but we need to be sure
  259. unsigned int cnt = 0;
  260. const char* sz = (const char*)stream->GetPtr();
  261. while (stream->GetI1())++cnt;
  262. mBackgroundImage = std::string(sz,cnt);
  263. }
  264. break;
  265. case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
  266. bHasBG = true;
  267. break;
  268. case Discreet3DS::CHUNK_MASTER_SCALE:
  269. // Scene master scaling factor
  270. mMasterScale = stream->GetF4();
  271. break;
  272. };
  273. ASSIMP_3DS_END_CHUNK();
  274. // recursively continue processing this hierarchy level
  275. return ParseObjectChunk();
  276. }
  277. // ------------------------------------------------------------------------------------------------
  278. void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
  279. {
  280. ASSIMP_3DS_BEGIN_CHUNK();
  281. // get chunk type
  282. switch (chunk.Flag)
  283. {
  284. case Discreet3DS::CHUNK_TRIMESH:
  285. {
  286. // this starts a new triangle mesh
  287. mScene->mMeshes.push_back(D3DS::Mesh());
  288. D3DS::Mesh& m = mScene->mMeshes.back();
  289. // Setup the name of the mesh
  290. m.mName = std::string(name, num);
  291. // Read mesh chunks
  292. ParseMeshChunk();
  293. }
  294. break;
  295. case Discreet3DS::CHUNK_LIGHT:
  296. {
  297. // This starts a new light
  298. aiLight* light = new aiLight();
  299. mScene->mLights.push_back(light);
  300. light->mName.Set(std::string(name, num));
  301. // First read the position of the light
  302. light->mPosition.x = stream->GetF4();
  303. light->mPosition.y = stream->GetF4();
  304. light->mPosition.z = stream->GetF4();
  305. light->mColorDiffuse = aiColor3D(1.f,1.f,1.f);
  306. // Now check for further subchunks (excluding color)
  307. int8_t* p = stream->GetPtr();
  308. ParseLightChunk();
  309. // The specular light color is identical the the diffuse light
  310. // color. The ambient light color is equal to the ambient base
  311. // color of the whole scene.
  312. light->mColorSpecular = light->mColorDiffuse;
  313. light->mColorAmbient = mClrAmbient;
  314. if (light->mType == aiLightSource_UNDEFINED)
  315. {
  316. // It must be a point light
  317. light->mType = aiLightSource_POINT;
  318. }}
  319. break;
  320. case Discreet3DS::CHUNK_CAMERA:
  321. {
  322. // This starts a new camera
  323. aiCamera* camera = new aiCamera();
  324. mScene->mCameras.push_back(camera);
  325. camera->mName.Set(std::string(name, num));
  326. // Camera position and look-at vector are difficult to handle.
  327. // If an animation track is given, we must make sure that
  328. // the track is relative to these values - or , easier
  329. // we must copy the information here to the node matrix of
  330. // the camera's parent in the graph.
  331. // First read the position of the camera
  332. camera->mPosition.x = stream->GetF4();
  333. camera->mPosition.y = stream->GetF4();
  334. camera->mPosition.z = stream->GetF4();
  335. // Then the camera target
  336. camera->mLookAt.x = stream->GetF4() - camera->mPosition.x;
  337. camera->mLookAt.y = stream->GetF4() - camera->mPosition.y;
  338. camera->mLookAt.z = stream->GetF4() - camera->mPosition.z;
  339. camera->mLookAt.Normalize();
  340. // And finally - the camera rotation angle, in
  341. // counter clockwise direction
  342. const float angle = AI_DEG_TO_RAD( stream->GetF4() );
  343. aiQuaternion quat(camera->mLookAt,angle);
  344. camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f);
  345. // Read the lense angle
  346. camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() );
  347. if (camera->mHorizontalFOV < 0.001f)
  348. camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f);
  349. }
  350. break;
  351. };
  352. ASSIMP_3DS_END_CHUNK();
  353. // recursively continue processing this hierarchy level
  354. return ParseChunk(name,num);
  355. }
  356. // ------------------------------------------------------------------------------------------------
  357. void Discreet3DSImporter::ParseLightChunk()
  358. {
  359. ASSIMP_3DS_BEGIN_CHUNK();
  360. aiLight* light = mScene->mLights.back();
  361. // get chunk type
  362. switch (chunk.Flag)
  363. {
  364. case Discreet3DS::CHUNK_SPOTLIGHT:
  365. // Now we can be sure that the light is a spot light
  366. light->mType = aiLightSource_SPOT;
  367. // We wouldn't need to normalize here, but we do it
  368. light->mDirection.x = stream->GetF4() - light->mPosition.x;
  369. light->mDirection.y = stream->GetF4() - light->mPosition.y;
  370. light->mDirection.z = stream->GetF4() - light->mPosition.z;
  371. light->mDirection.Normalize();
  372. // Now the hotspot and falloff angles - in degrees
  373. light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() );
  374. // FIX: the falloff angle is just an offset
  375. light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() );
  376. break;
  377. // intensity multiplier
  378. case Discreet3DS::CHUNK_DL_MULTIPLIER:
  379. light->mColorDiffuse = light->mColorDiffuse * stream->GetF4();
  380. break;
  381. // light color
  382. case Discreet3DS::CHUNK_RGBF:
  383. case Discreet3DS::CHUNK_LINRGBF:
  384. light->mColorDiffuse.r *= stream->GetF4();
  385. light->mColorDiffuse.g *= stream->GetF4();
  386. light->mColorDiffuse.b *= stream->GetF4();
  387. break;
  388. // light attenuation
  389. case Discreet3DS::CHUNK_DL_ATTENUATE:
  390. light->mAttenuationLinear = stream->GetF4();
  391. break;
  392. };
  393. ASSIMP_3DS_END_CHUNK();
  394. // recursively continue processing this hierarchy level
  395. return ParseLightChunk();
  396. }
  397. // ------------------------------------------------------------------------------------------------
  398. void Discreet3DSImporter::ParseCameraChunk()
  399. {
  400. ASSIMP_3DS_BEGIN_CHUNK();
  401. aiCamera* camera = mScene->mCameras.back();
  402. // get chunk type
  403. switch (chunk.Flag)
  404. {
  405. // near and far clip plane
  406. case Discreet3DS::CHUNK_CAM_RANGES:
  407. camera->mClipPlaneNear = stream->GetF4();
  408. camera->mClipPlaneFar = stream->GetF4();
  409. break;
  410. }
  411. ASSIMP_3DS_END_CHUNK();
  412. // recursively continue processing this hierarchy level
  413. return ParseCameraChunk();
  414. }
  415. // ------------------------------------------------------------------------------------------------
  416. void Discreet3DSImporter::ParseKeyframeChunk()
  417. {
  418. ASSIMP_3DS_BEGIN_CHUNK();
  419. // get chunk type
  420. switch (chunk.Flag)
  421. {
  422. case Discreet3DS::CHUNK_TRACKCAMTGT:
  423. case Discreet3DS::CHUNK_SPOTLIGHT:
  424. case Discreet3DS::CHUNK_TRACKCAMERA:
  425. case Discreet3DS::CHUNK_TRACKINFO:
  426. case Discreet3DS::CHUNK_TRACKLIGHT:
  427. case Discreet3DS::CHUNK_TRACKLIGTGT:
  428. // this starts a new mesh hierarchy chunk
  429. ParseHierarchyChunk(chunk.Flag);
  430. break;
  431. };
  432. ASSIMP_3DS_END_CHUNK();
  433. // recursively continue processing this hierarchy level
  434. return ParseKeyframeChunk();
  435. }
  436. // ------------------------------------------------------------------------------------------------
  437. // Little helper function for ParseHierarchyChunk
  438. void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
  439. {
  440. if (!pcCurrent)
  441. {
  442. mRootNode->push_back(pcNode);
  443. return;
  444. }
  445. if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos)
  446. {
  447. if(pcCurrent->mParent)pcCurrent->mParent->push_back(pcNode);
  448. else pcCurrent->push_back(pcNode);
  449. return;
  450. }
  451. return InverseNodeSearch(pcNode,pcCurrent->mParent);
  452. }
  453. // ------------------------------------------------------------------------------------------------
  454. // Find a node with a specific name in the import hierarchy
  455. D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
  456. {
  457. if (root->mName == name)return root;
  458. for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();
  459. it != root->mChildren.end(); ++it)
  460. {
  461. D3DS::Node* nd;
  462. if (( nd = FindNode(*it,name)))return nd;
  463. }
  464. return NULL;
  465. }
  466. // ------------------------------------------------------------------------------------------------
  467. // Binary predicate for std::unique()
  468. template <class T>
  469. bool KeyUniqueCompare(const T& first, const T& second)
  470. {
  471. return first.mTime == second.mTime;
  472. }
  473. // ------------------------------------------------------------------------------------------------
  474. // Skip some additional import data.
  475. void Discreet3DSImporter::SkipTCBInfo()
  476. {
  477. unsigned int flags = stream->GetI2();
  478. if (!flags)
  479. {
  480. //////////////////////////////////////////////////////////////////////////
  481. // Currently we can't do anything with these values. They occur
  482. // quite rare, so it wouldn't be worth the effort implementing
  483. // them. 3DS ist not really suitable for complex animations,
  484. // so full support is not required.
  485. //////////////////////////////////////////////////////////////////////////
  486. DefaultLogger::get()->warn("3DS: Skipping TCB animation info");
  487. }
  488. if (flags & Discreet3DS::KEY_USE_TENS)
  489. stream->IncPtr(4);
  490. if (flags & Discreet3DS::KEY_USE_BIAS)
  491. stream->IncPtr(4);
  492. if (flags & Discreet3DS::KEY_USE_CONT)
  493. stream->IncPtr(4);
  494. if (flags & Discreet3DS::KEY_USE_EASE_FROM)
  495. stream->IncPtr(4);
  496. if (flags & Discreet3DS::KEY_USE_EASE_TO)
  497. stream->IncPtr(4);
  498. }
  499. // ------------------------------------------------------------------------------------------------
  500. // Read hierarchy and keyframe info
  501. void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
  502. {
  503. ASSIMP_3DS_BEGIN_CHUNK();
  504. // get chunk type
  505. switch (chunk.Flag)
  506. {
  507. case Discreet3DS::CHUNK_TRACKOBJNAME:
  508. // This is the name of the object to which the track applies
  509. // The chunk also defines the position of this object in the
  510. // hierarchy.
  511. {
  512. // First of all: get the name of the object
  513. unsigned int cnt = 0;
  514. const char* sz = (const char*)stream->GetPtr();
  515. while (stream->GetI1())++cnt;
  516. std::string name = std::string(sz,cnt);
  517. // Now find out whether we have this node already
  518. // (target animation channels are stored with a
  519. // separate object ID)
  520. D3DS::Node* pcNode = FindNode(mRootNode,name);
  521. if (pcNode)
  522. {
  523. // Make this node the current node
  524. mCurrentNode = pcNode;
  525. break;
  526. }
  527. pcNode = new D3DS::Node();
  528. pcNode->mName = name;
  529. // There are two unknown values which we can safely ignore
  530. stream->IncPtr(4);
  531. // Now read the hierarchy position of the object
  532. uint16_t hierarchy = stream->GetI2() + 1;
  533. pcNode->mHierarchyPos = hierarchy;
  534. pcNode->mHierarchyIndex = mLastNodeIndex;
  535. // And find a proper position in the graph for it
  536. if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy)
  537. {
  538. // add to the parent of the last touched node
  539. mCurrentNode->mParent->push_back(pcNode);
  540. mLastNodeIndex++;
  541. }
  542. else if(hierarchy >= mLastNodeIndex)
  543. {
  544. // place it at the current position in the hierarchy
  545. mCurrentNode->push_back(pcNode);
  546. mLastNodeIndex = hierarchy;
  547. }
  548. else
  549. {
  550. // need to go back to the specified position in the hierarchy.
  551. InverseNodeSearch(pcNode,mCurrentNode);
  552. mLastNodeIndex++;
  553. }
  554. // Make this node the current node
  555. mCurrentNode = pcNode;
  556. }
  557. break;
  558. case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME:
  559. // This is the "real" name of a $$$DUMMY object
  560. {
  561. const char* sz = (const char*) stream->GetPtr();
  562. while (stream->GetI1());
  563. // mCurrentNode->mDummyName = std::string(sz);
  564. // FIX: if object name is DUMMY, take this one instead
  565. if (mCurrentNode->mName == "$$$DUMMY") {
  566. //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
  567. mCurrentNode->mName = std::string(sz);
  568. break;
  569. }
  570. }
  571. break;
  572. case Discreet3DS::CHUNK_TRACKPIVOT:
  573. if ( Discreet3DS::CHUNK_TRACKINFO != parent)
  574. {
  575. DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object");
  576. break;
  577. }
  578. // Pivot = origin of rotation and scaling
  579. mCurrentNode->vPivot.x = stream->GetF4();
  580. mCurrentNode->vPivot.y = stream->GetF4();
  581. mCurrentNode->vPivot.z = stream->GetF4();
  582. break;
  583. // ////////////////////////////////////////////////////////////////////
  584. // POSITION KEYFRAME
  585. case Discreet3DS::CHUNK_TRACKPOS:
  586. {
  587. stream->IncPtr(10);
  588. const unsigned int numFrames = stream->GetI4();
  589. bool sortKeys = false;
  590. // This could also be meant as the target position for
  591. // (targeted) lights and cameras
  592. std::vector<aiVectorKey>* l;
  593. if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent)
  594. {
  595. l = & mCurrentNode->aTargetPositionKeys;
  596. }
  597. else l = & mCurrentNode->aPositionKeys;
  598. l->reserve(numFrames);
  599. for (unsigned int i = 0; i < numFrames;++i)
  600. {
  601. const unsigned int fidx = stream->GetI4();
  602. // Setup a new position key
  603. aiVectorKey v;
  604. v.mTime = (double)fidx;
  605. SkipTCBInfo();
  606. v.mValue.x = stream->GetF4();
  607. v.mValue.y = stream->GetF4();
  608. v.mValue.z = stream->GetF4();
  609. // check whether we'll need to sort the keys
  610. if (!l->empty() && v.mTime <= l->back().mTime)
  611. sortKeys = true;
  612. // Add the new keyframe to the list
  613. l->push_back(v);
  614. }
  615. // Sort all keys with ascending time values and remove duplicates?
  616. if (sortKeys)
  617. {
  618. std::stable_sort(l->begin(),l->end());
  619. l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
  620. }}
  621. break;
  622. // ////////////////////////////////////////////////////////////////////
  623. // CAMERA ROLL KEYFRAME
  624. case Discreet3DS::CHUNK_TRACKROLL:
  625. {
  626. // roll keys are accepted for cameras only
  627. if (parent != Discreet3DS::CHUNK_TRACKCAMERA)
  628. {
  629. DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
  630. break;
  631. }
  632. bool sortKeys = false;
  633. std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys;
  634. stream->IncPtr(10);
  635. const unsigned int numFrames = stream->GetI4();
  636. l->reserve(numFrames);
  637. for (unsigned int i = 0; i < numFrames;++i)
  638. {
  639. const unsigned int fidx = stream->GetI4();
  640. // Setup a new position key
  641. aiFloatKey v;
  642. v.mTime = (double)fidx;
  643. // This is just a single float
  644. SkipTCBInfo();
  645. v.mValue = stream->GetF4();
  646. // Check whether we'll need to sort the keys
  647. if (!l->empty() && v.mTime <= l->back().mTime)
  648. sortKeys = true;
  649. // Add the new keyframe to the list
  650. l->push_back(v);
  651. }
  652. // Sort all keys with ascending time values and remove duplicates?
  653. if (sortKeys)
  654. {
  655. std::stable_sort(l->begin(),l->end());
  656. l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() );
  657. }}
  658. break;
  659. // ////////////////////////////////////////////////////////////////////
  660. // CAMERA FOV KEYFRAME
  661. case Discreet3DS::CHUNK_TRACKFOV:
  662. {
  663. DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
  664. "This is not supported");
  665. }
  666. break;
  667. // ////////////////////////////////////////////////////////////////////
  668. // ROTATION KEYFRAME
  669. case Discreet3DS::CHUNK_TRACKROTATE:
  670. {
  671. stream->IncPtr(10);
  672. const unsigned int numFrames = stream->GetI4();
  673. bool sortKeys = false;
  674. std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
  675. l->reserve(numFrames);
  676. for (unsigned int i = 0; i < numFrames;++i)
  677. {
  678. const unsigned int fidx = stream->GetI4();
  679. SkipTCBInfo();
  680. aiQuatKey v;
  681. v.mTime = (double)fidx;
  682. // The rotation keyframe is given as an axis-angle pair
  683. const float rad = stream->GetF4();
  684. aiVector3D axis;
  685. axis.x = stream->GetF4();
  686. axis.y = stream->GetF4();
  687. axis.z = stream->GetF4();
  688. if (!axis.x && !axis.y && !axis.z)
  689. axis.y = 1.f;
  690. // Construct a rotation quaternion from the axis-angle pair
  691. v.mValue = aiQuaternion(axis,rad);
  692. // Check whether we'll need to sort the keys
  693. if (!l->empty() && v.mTime <= l->back().mTime)
  694. sortKeys = true;
  695. // add the new keyframe to the list
  696. l->push_back(v);
  697. }
  698. // Sort all keys with ascending time values and remove duplicates?
  699. if (sortKeys)
  700. {
  701. std::stable_sort(l->begin(),l->end());
  702. l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() );
  703. }}
  704. break;
  705. // ////////////////////////////////////////////////////////////////////
  706. // SCALING KEYFRAME
  707. case Discreet3DS::CHUNK_TRACKSCALE:
  708. {
  709. stream->IncPtr(10);
  710. const unsigned int numFrames = stream->GetI2();
  711. stream->IncPtr(2);
  712. bool sortKeys = false;
  713. std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
  714. l->reserve(numFrames);
  715. for (unsigned int i = 0; i < numFrames;++i)
  716. {
  717. const unsigned int fidx = stream->GetI4();
  718. SkipTCBInfo();
  719. // Setup a new key
  720. aiVectorKey v;
  721. v.mTime = (double)fidx;
  722. // ... and read its value
  723. v.mValue.x = stream->GetF4();
  724. v.mValue.y = stream->GetF4();
  725. v.mValue.z = stream->GetF4();
  726. // check whether we'll need to sort the keys
  727. if (!l->empty() && v.mTime <= l->back().mTime)
  728. sortKeys = true;
  729. // Remove zero-scalings
  730. if (!v.mValue.x)v.mValue.x = 1.f;
  731. if (!v.mValue.y)v.mValue.y = 1.f;
  732. if (!v.mValue.z)v.mValue.z = 1.f;
  733. l->push_back(v);
  734. }
  735. // Sort all keys with ascending time values and remove duplicates?
  736. if (sortKeys)
  737. {
  738. std::stable_sort(l->begin(),l->end());
  739. l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
  740. }}
  741. break;
  742. };
  743. ASSIMP_3DS_END_CHUNK();
  744. // recursively continue processing this hierarchy level
  745. return ParseHierarchyChunk(parent);
  746. }
  747. // ------------------------------------------------------------------------------------------------
  748. // Read a face chunk - it contains smoothing groups and material assignments
  749. void Discreet3DSImporter::ParseFaceChunk()
  750. {
  751. ASSIMP_3DS_BEGIN_CHUNK();
  752. // Get the mesh we're currently working on
  753. D3DS::Mesh& mMesh = mScene->mMeshes.back();
  754. // Get chunk type
  755. switch (chunk.Flag)
  756. {
  757. case Discreet3DS::CHUNK_SMOOLIST:
  758. {
  759. // This is the list of smoothing groups - a bitfield for
  760. // every frame. Up to 32 smoothing groups assigned to a
  761. // face.
  762. unsigned int num = chunkSize/4, m = 0;
  763. for (std::vector<D3DS::Face>::iterator i = mMesh.mFaces.begin();
  764. m != num;++i, ++m)
  765. {
  766. // nth bit is set for nth smoothing group
  767. (*i).iSmoothGroup = stream->GetI4();
  768. }}
  769. break;
  770. case Discreet3DS::CHUNK_FACEMAT:
  771. {
  772. // at fist an asciiz with the material name
  773. const char* sz = (const char*)stream->GetPtr();
  774. while (stream->GetI1());
  775. // find the index of the material
  776. unsigned int idx = 0xcdcdcdcd, cnt = 0;
  777. for (std::vector<D3DS::Material>::const_iterator
  778. i = mScene->mMaterials.begin();
  779. i != mScene->mMaterials.end();++i,++cnt)
  780. {
  781. // compare case-independent to be sure it works
  782. if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str()))
  783. {
  784. idx = cnt;
  785. break;
  786. }
  787. }
  788. if (0xcdcdcdcd == idx)
  789. {
  790. DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
  791. // --------------------------------------------------------------
  792. // This material is not known. Ignore this. We will later
  793. // assign the default material to all faces using *this*
  794. // material. We use 0xcdcdcdcd as special value to indicate this.
  795. // --------------------------------------------------------------
  796. }
  797. // Now continue and read all material indices
  798. cnt = (uint16_t)stream->GetI2();
  799. for (unsigned int i = 0; i < cnt;++i) {
  800. unsigned int fidx = (uint16_t)stream->GetI2();
  801. // check range
  802. if (fidx >= mMesh.mFaceMaterials.size()) {
  803. DefaultLogger::get()->error("3DS: Invalid face index in face material list");
  804. }
  805. else mMesh.mFaceMaterials[fidx] = idx;
  806. }}
  807. break;
  808. };
  809. ASSIMP_3DS_END_CHUNK();
  810. // recursively continue processing this hierarchy level
  811. return ParseFaceChunk();
  812. }
  813. // ------------------------------------------------------------------------------------------------
  814. // Read a mesh chunk. Here's the actual mesh data
  815. void Discreet3DSImporter::ParseMeshChunk()
  816. {
  817. ASSIMP_3DS_BEGIN_CHUNK();
  818. // Get the mesh we're currently working on
  819. D3DS::Mesh& mMesh = mScene->mMeshes.back();
  820. // get chunk type
  821. switch (chunk.Flag)
  822. {
  823. case Discreet3DS::CHUNK_VERTLIST:
  824. {
  825. // This is the list of all vertices in the current mesh
  826. int num = (int)(uint16_t)stream->GetI2();
  827. mMesh.mPositions.reserve(num);
  828. while (num-- > 0)
  829. {
  830. aiVector3D v;
  831. v.x = stream->GetF4();
  832. v.y = stream->GetF4();
  833. v.z = stream->GetF4();
  834. mMesh.mPositions.push_back(v);
  835. }}
  836. break;
  837. case Discreet3DS::CHUNK_TRMATRIX:
  838. {
  839. // This is the RLEATIVE transformation matrix of the
  840. // current mesh. However, all vertices are pretransformed
  841. mMesh.mMat.a1 = stream->GetF4();
  842. mMesh.mMat.b1 = stream->GetF4();
  843. mMesh.mMat.c1 = stream->GetF4();
  844. mMesh.mMat.a2 = stream->GetF4();
  845. mMesh.mMat.b2 = stream->GetF4();
  846. mMesh.mMat.c2 = stream->GetF4();
  847. mMesh.mMat.a3 = stream->GetF4();
  848. mMesh.mMat.b3 = stream->GetF4();
  849. mMesh.mMat.c3 = stream->GetF4();
  850. mMesh.mMat.a4 = stream->GetF4();
  851. mMesh.mMat.b4 = stream->GetF4();
  852. mMesh.mMat.c4 = stream->GetF4();
  853. // Now check whether the matrix has got a negative determinant
  854. // If yes, we need to flip all vertices' Z axis ....
  855. // This code has been taken from lib3ds
  856. if (mMesh.mMat.Determinant() < 0.0f) {
  857. // Compute the inverse of the matrix
  858. aiMatrix4x4 mInv = mMesh.mMat;
  859. mInv.Inverse();
  860. aiMatrix4x4 mMe = mMesh.mMat;
  861. mMe.c1 *= -1.0f;
  862. mMe.c2 *= -1.0f;
  863. mMe.c3 *= -1.0f;
  864. mMe.c4 *= -1.0f;
  865. mInv = mInv * mMe;
  866. // Now transform all vertices
  867. for (unsigned int i = 0; i < (unsigned int)mMesh.mPositions.size();++i)
  868. {
  869. aiVector3D a,c;
  870. a = mMesh.mPositions[i];
  871. c[0]= mInv[0][0]*a[0] + mInv[1][0]*a[1] + mInv[2][0]*a[2] + mInv[3][0];
  872. c[1]= mInv[0][1]*a[0] + mInv[1][1]*a[1] + mInv[2][1]*a[2] + mInv[3][1];
  873. c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2];
  874. mMesh.mPositions[i] = c;
  875. }
  876. DefaultLogger::get()->info("3DS: Flipping mesh Z-Axis");
  877. }}
  878. break;
  879. case Discreet3DS::CHUNK_MAPLIST:
  880. {
  881. // This is the list of all UV coords in the current mesh
  882. int num = (int)(uint16_t)stream->GetI2();
  883. mMesh.mTexCoords.reserve(num);
  884. while (num-- > 0)
  885. {
  886. aiVector3D v;
  887. v.x = stream->GetF4();
  888. v.y = stream->GetF4();
  889. mMesh.mTexCoords.push_back(v);
  890. }}
  891. break;
  892. case Discreet3DS::CHUNK_FACELIST:
  893. {
  894. // This is the list of all faces in the current mesh
  895. int num = (int)(uint16_t)stream->GetI2();
  896. mMesh.mFaces.reserve(num);
  897. while (num-- > 0)
  898. {
  899. // 3DS faces are ALWAYS triangles
  900. mMesh.mFaces.push_back(D3DS::Face());
  901. D3DS::Face& sFace = mMesh.mFaces.back();
  902. sFace.mIndices[0] = (uint16_t)stream->GetI2();
  903. sFace.mIndices[1] = (uint16_t)stream->GetI2();
  904. sFace.mIndices[2] = (uint16_t)stream->GetI2();
  905. stream->IncPtr(2); // skip edge visibility flag
  906. }
  907. // Resize the material array (0xcdcdcdcd marks the
  908. // default material; so if a face is not referenced
  909. // by a material $$DEFAULT will be assigned to it)
  910. mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd);
  911. // Larger 3DS files could have multiple FACE chunks here
  912. chunkSize = stream->GetRemainingSizeToLimit();
  913. if (chunkSize > sizeof(Discreet3DS::Chunk))
  914. ParseFaceChunk();
  915. }
  916. break;
  917. };
  918. ASSIMP_3DS_END_CHUNK();
  919. // recursively continue processing this hierarchy level
  920. return ParseMeshChunk();
  921. }
  922. // ------------------------------------------------------------------------------------------------
  923. // Read a 3DS material chunk
  924. void Discreet3DSImporter::ParseMaterialChunk()
  925. {
  926. ASSIMP_3DS_BEGIN_CHUNK();
  927. // get chunk type
  928. switch (chunk.Flag)
  929. {
  930. case Discreet3DS::CHUNK_MAT_MATNAME:
  931. {
  932. // The material name string is already zero-terminated, but
  933. // we need to be sure ...
  934. const char* sz = (const char*)stream->GetPtr();
  935. unsigned int cnt = 0;
  936. while (stream->GetI1())++cnt;
  937. if (!cnt)
  938. {
  939. // This may not be, we use the default name instead
  940. DefaultLogger::get()->error("3DS: Empty material name");
  941. }
  942. else mScene->mMaterials.back().mName = std::string(sz,cnt);
  943. }
  944. break;
  945. case Discreet3DS::CHUNK_MAT_DIFFUSE:
  946. {
  947. // This is the diffuse material color
  948. aiColor3D* pc = &mScene->mMaterials.back().mDiffuse;
  949. ParseColorChunk(pc);
  950. if (is_qnan(pc->r)) {
  951. // color chunk is invalid. Simply ignore it
  952. DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk");
  953. pc->r = pc->g = pc->b = 1.0f;
  954. }}
  955. break;
  956. case Discreet3DS::CHUNK_MAT_SPECULAR:
  957. {
  958. // This is the specular material color
  959. aiColor3D* pc = &mScene->mMaterials.back().mSpecular;
  960. ParseColorChunk(pc);
  961. if (is_qnan(pc->r)) {
  962. // color chunk is invalid. Simply ignore it
  963. DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk");
  964. pc->r = pc->g = pc->b = 1.0f;
  965. }}
  966. break;
  967. case Discreet3DS::CHUNK_MAT_AMBIENT:
  968. {
  969. // This is the ambient material color
  970. aiColor3D* pc = &mScene->mMaterials.back().mAmbient;
  971. ParseColorChunk(pc);
  972. if (is_qnan(pc->r)) {
  973. // color chunk is invalid. Simply ignore it
  974. DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk");
  975. pc->r = pc->g = pc->b = 0.0f;
  976. }}
  977. break;
  978. case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
  979. {
  980. // This is the emissive material color
  981. aiColor3D* pc = &mScene->mMaterials.back().mEmissive;
  982. ParseColorChunk(pc);
  983. if (is_qnan(pc->r)) {
  984. // color chunk is invalid. Simply ignore it
  985. DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk");
  986. pc->r = pc->g = pc->b = 0.0f;
  987. }}
  988. break;
  989. case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
  990. {
  991. // This is the material's transparency
  992. float* pcf = &mScene->mMaterials.back().mTransparency;
  993. *pcf = ParsePercentageChunk();
  994. // NOTE: transparency, not opacity
  995. if (is_qnan(*pcf))*pcf = 1.0f;
  996. else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
  997. }
  998. break;
  999. case Discreet3DS::CHUNK_MAT_SHADING:
  1000. // This is the material shading mode
  1001. mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2();
  1002. break;
  1003. case Discreet3DS::CHUNK_MAT_TWO_SIDE:
  1004. // This is the two-sided flag
  1005. mScene->mMaterials.back().mTwoSided = true;
  1006. break;
  1007. case Discreet3DS::CHUNK_MAT_SHININESS:
  1008. { // This is the shininess of the material
  1009. float* pcf = &mScene->mMaterials.back().mSpecularExponent;
  1010. *pcf = ParsePercentageChunk();
  1011. if (is_qnan(*pcf))*pcf = 0.0f;
  1012. else *pcf *= (float)0xFFFF;
  1013. }
  1014. break;
  1015. case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
  1016. { // This is the shininess strength of the material
  1017. float* pcf = &mScene->mMaterials.back().mShininessStrength;
  1018. *pcf = ParsePercentageChunk();
  1019. if (is_qnan(*pcf))*pcf = 0.0f;
  1020. else *pcf *= (float)0xffff / 100.0f;
  1021. }
  1022. break;
  1023. case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
  1024. { // This is the self illumination strength of the material
  1025. float f = ParsePercentageChunk();
  1026. if (is_qnan(f))f = 0.0f;
  1027. else f *= (float)0xFFFF / 100.0f;
  1028. mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
  1029. }
  1030. break;
  1031. // Parse texture chunks
  1032. case Discreet3DS::CHUNK_MAT_TEXTURE:
  1033. // Diffuse texture
  1034. ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse);
  1035. break;
  1036. case Discreet3DS::CHUNK_MAT_BUMPMAP:
  1037. // Height map
  1038. ParseTextureChunk(&mScene->mMaterials.back().sTexBump);
  1039. break;
  1040. case Discreet3DS::CHUNK_MAT_OPACMAP:
  1041. // Opacity texture
  1042. ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity);
  1043. break;
  1044. case Discreet3DS::CHUNK_MAT_MAT_SHINMAP:
  1045. // Shininess map
  1046. ParseTextureChunk(&mScene->mMaterials.back().sTexShininess);
  1047. break;
  1048. case Discreet3DS::CHUNK_MAT_SPECMAP:
  1049. // Specular map
  1050. ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular);
  1051. break;
  1052. case Discreet3DS::CHUNK_MAT_SELFIMAP:
  1053. // Self-illumination (emissive) map
  1054. ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive);
  1055. break;
  1056. case Discreet3DS::CHUNK_MAT_REFLMAP:
  1057. // Reflection map
  1058. ParseTextureChunk(&mScene->mMaterials.back().sTexReflective);
  1059. break;
  1060. };
  1061. ASSIMP_3DS_END_CHUNK();
  1062. // recursively continue processing this hierarchy level
  1063. return ParseMaterialChunk();
  1064. }
  1065. // ------------------------------------------------------------------------------------------------
  1066. void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
  1067. {
  1068. ASSIMP_3DS_BEGIN_CHUNK();
  1069. // get chunk type
  1070. switch (chunk.Flag)
  1071. {
  1072. case Discreet3DS::CHUNK_MAPFILE:
  1073. {
  1074. // The material name string is already zero-terminated, but
  1075. // we need to be sure ...
  1076. const char* sz = (const char*)stream->GetPtr();
  1077. unsigned int cnt = 0;
  1078. while (stream->GetI1())++cnt;
  1079. pcOut->mMapName = std::string(sz,cnt);
  1080. }
  1081. break;
  1082. case Discreet3DS::CHUNK_PERCENTF:
  1083. // Manually parse the blend factor
  1084. pcOut->mTextureBlend = stream->GetF4();
  1085. break;
  1086. case Discreet3DS::CHUNK_PERCENTW:
  1087. // Manually parse the blend factor
  1088. pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f;
  1089. break;
  1090. case Discreet3DS::CHUNK_MAT_MAP_USCALE:
  1091. // Texture coordinate scaling in the U direction
  1092. pcOut->mScaleU = stream->GetF4();
  1093. if (0.0f == pcOut->mScaleU)
  1094. {
  1095. DefaultLogger::get()->warn("Texture coordinate scaling in the "
  1096. "x direction is zero. Assuming 1");
  1097. pcOut->mScaleU = 1.0f;
  1098. }
  1099. break;
  1100. case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
  1101. // Texture coordinate scaling in the V direction
  1102. pcOut->mScaleV = stream->GetF4();
  1103. if (0.0f == pcOut->mScaleV)
  1104. {
  1105. DefaultLogger::get()->warn("Texture coordinate scaling in the "
  1106. "y direction is zero. Assuming 1");
  1107. pcOut->mScaleV = 1.0f;
  1108. }
  1109. break;
  1110. case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
  1111. // Texture coordinate offset in the U direction
  1112. pcOut->mOffsetU = -stream->GetF4();
  1113. break;
  1114. case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
  1115. // Texture coordinate offset in the V direction
  1116. pcOut->mOffsetV = stream->GetF4();
  1117. break;
  1118. case Discreet3DS::CHUNK_MAT_MAP_ANG:
  1119. // Texture coordinate rotation, CCW in DEGREES
  1120. pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() );
  1121. break;
  1122. case Discreet3DS::CHUNK_MAT_MAP_TILING:
  1123. {
  1124. const uint16_t iFlags = stream->GetI2();
  1125. // Get the mapping mode (for both axes)
  1126. if (iFlags & 0x2u)
  1127. pcOut->mMapMode = aiTextureMapMode_Mirror;
  1128. else if (iFlags & 0x10u)
  1129. pcOut->mMapMode = aiTextureMapMode_Decal;
  1130. // wrapping in all remaining cases
  1131. else pcOut->mMapMode = aiTextureMapMode_Wrap;
  1132. }
  1133. break;
  1134. };
  1135. ASSIMP_3DS_END_CHUNK();
  1136. // recursively continue processing this hierarchy level
  1137. return ParseTextureChunk(pcOut);
  1138. }
  1139. // ------------------------------------------------------------------------------------------------
  1140. // Read a percentage chunk
  1141. float Discreet3DSImporter::ParsePercentageChunk()
  1142. {
  1143. Discreet3DS::Chunk chunk;
  1144. ReadChunk(&chunk);
  1145. if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag)
  1146. return stream->GetF4();
  1147. else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag)
  1148. return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF;
  1149. return std::numeric_limits<float>::quiet_NaN();
  1150. }
  1151. // ------------------------------------------------------------------------------------------------
  1152. // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
  1153. void Discreet3DSImporter::ParseColorChunk(aiColor3D* out,
  1154. bool acceptPercent)
  1155. {
  1156. ai_assert(out != NULL);
  1157. // error return value
  1158. const float qnan = std::numeric_limits<float>::quiet_NaN();
  1159. static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan);
  1160. Discreet3DS::Chunk chunk;
  1161. ReadChunk(&chunk);
  1162. const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk);
  1163. bool bGamma = false;
  1164. // Get the type of the chunk
  1165. switch(chunk.Flag)
  1166. {
  1167. case Discreet3DS::CHUNK_LINRGBF:
  1168. bGamma = true;
  1169. case Discreet3DS::CHUNK_RGBF:
  1170. if (sizeof(float) * 3 > diff)
  1171. {
  1172. *out = clrError;
  1173. return;
  1174. }
  1175. out->r = stream->GetF4();
  1176. out->g = stream->GetF4();
  1177. out->b = stream->GetF4();
  1178. break;
  1179. case Discreet3DS::CHUNK_LINRGBB:
  1180. bGamma = true;
  1181. case Discreet3DS::CHUNK_RGBB:
  1182. if (sizeof(char) * 3 > diff)
  1183. {
  1184. *out = clrError;
  1185. return;
  1186. }
  1187. out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
  1188. out->g = (float)(uint8_t)stream->GetI1() / 255.0f;
  1189. out->b = (float)(uint8_t)stream->GetI1() / 255.0f;
  1190. break;
  1191. // Percentage chunks are accepted, too.
  1192. case Discreet3DS::CHUNK_PERCENTF:
  1193. if (acceptPercent && 4 <= diff)
  1194. {
  1195. out->g = out->b = out->r = stream->GetF4();
  1196. break;
  1197. }
  1198. *out = clrError;
  1199. return;
  1200. case Discreet3DS::CHUNK_PERCENTW:
  1201. if (acceptPercent && 1 <= diff)
  1202. {
  1203. out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
  1204. break;
  1205. }
  1206. *out = clrError;
  1207. return;
  1208. default:
  1209. stream->IncPtr(diff);
  1210. // Skip unknown chunks, hope this won't cause any problems.
  1211. return ParseColorChunk(out,acceptPercent);
  1212. };
  1213. }
  1214. #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER