3DSLoader.cpp 40 KB

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