3DSConverter.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /** @file Implementation of the 3ds importer class */
  2. #include "3DSLoader.h"
  3. #include "MaterialSystem.h"
  4. #include "../include/IOStream.h"
  5. #include "../include/IOSystem.h"
  6. #include "../include/aiMesh.h"
  7. #include "../include/aiScene.h"
  8. #include "../include/aiAssert.h"
  9. #include <boost/scoped_ptr.hpp>
  10. using namespace Assimp;
  11. // ------------------------------------------------------------------------------------------------
  12. void Dot3DSImporter::ReplaceDefaultMaterial()
  13. {
  14. // try to find an existing material that matches the
  15. // typical default material setting:
  16. // - no textures
  17. // - diffuse color (in grey!)
  18. // NOTE: This is here to workaround the fact that some
  19. // exporters are writing a default material, too.
  20. unsigned int iIndex = 0xcdcdcdcd;
  21. for (unsigned int i = 0; i < this->mScene->mMaterials.size();++i)
  22. {
  23. if (std::string::npos == this->mScene->mMaterials[i].mName.find("default") &&
  24. std::string::npos == this->mScene->mMaterials[i].mName.find("DEFAULT"))continue;
  25. if (this->mScene->mMaterials[i].mDiffuse.r !=
  26. this->mScene->mMaterials[i].mDiffuse.g ||
  27. this->mScene->mMaterials[i].mDiffuse.r !=
  28. this->mScene->mMaterials[i].mDiffuse.b)continue;
  29. if (this->mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
  30. this->mScene->mMaterials[i].sTexBump.mMapName.length()!= 0 ||
  31. this->mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
  32. this->mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
  33. this->mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
  34. this->mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )continue;
  35. iIndex = i;
  36. }
  37. if (0xcdcdcdcd == iIndex)iIndex = this->mScene->mMaterials.size();
  38. // now iterate through all meshes and through all faces and
  39. // find all faces that are using the default material
  40. unsigned int iCnt = 0;
  41. for (std::vector<Dot3DS::Mesh>::iterator
  42. i = this->mScene->mMeshes.begin();
  43. i != this->mScene->mMeshes.end();++i)
  44. {
  45. for (std::vector<unsigned int>::iterator
  46. a = (*i).mFaceMaterials.begin();
  47. a != (*i).mFaceMaterials.end();++a)
  48. {
  49. // NOTE: The additional check seems to be necessary,
  50. // some exporters seem to generate invalid data here
  51. if (0xcdcdcdcd == (*a) || (*a) >= this->mScene->mMaterials.size())
  52. {
  53. (*a) = iIndex;
  54. ++iCnt;
  55. }
  56. }
  57. }
  58. if (0 != iCnt && iIndex == this->mScene->mMaterials.size())
  59. {
  60. // we need to create our own default material
  61. Dot3DS::Material sMat;
  62. sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
  63. sMat.mName = "%%%DEFAULT";
  64. this->mScene->mMaterials.push_back(sMat);
  65. }
  66. return;
  67. }
  68. // ------------------------------------------------------------------------------------------------
  69. void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh)
  70. {
  71. for (std::vector< Dot3DS::Face >::iterator
  72. i = sMesh->mFaces.begin();
  73. i != sMesh->mFaces.end();++i)
  74. {
  75. // check whether all indices are in range
  76. if ((*i).i1 >= sMesh->mPositions.size())
  77. {
  78. (*i).i1 = sMesh->mPositions.size()-1;
  79. }
  80. if ((*i).i2 >= sMesh->mPositions.size())
  81. {
  82. (*i).i2 = sMesh->mPositions.size()-1;
  83. }
  84. if ((*i).i3 >= sMesh->mPositions.size())
  85. {
  86. (*i).i3 = sMesh->mPositions.size()-1;
  87. }
  88. }
  89. return;
  90. }
  91. // ------------------------------------------------------------------------------------------------
  92. void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
  93. {
  94. std::vector<aiVector3D> vNew;
  95. vNew.resize(sMesh->mFaces.size() * 3);
  96. std::vector<aiVector2D> vNew2;
  97. // TODO: Remove this step. By maintaining a small LUT it
  98. // would be possible to do this directly in the parsing step
  99. unsigned int iBase = 0;
  100. if (0 != sMesh->mTexCoords.size())
  101. {
  102. vNew2.resize(sMesh->mFaces.size() * 3);
  103. for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
  104. {
  105. // position and texture coordinates
  106. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i1];
  107. vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].i1];
  108. sMesh->mFaces[i].i1 = iBase++;
  109. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i2];
  110. vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].i2];
  111. sMesh->mFaces[i].i2 = iBase++;
  112. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i3];
  113. vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].i3];
  114. sMesh->mFaces[i].i3 = iBase++;
  115. }
  116. }
  117. else
  118. {
  119. for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
  120. {
  121. // position only
  122. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i1];
  123. sMesh->mFaces[i].i1 = iBase++;
  124. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i2];
  125. sMesh->mFaces[i].i2 = iBase++;
  126. vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].i3];
  127. sMesh->mFaces[i].i3 = iBase++;
  128. }
  129. }
  130. sMesh->mPositions = vNew;
  131. sMesh->mTexCoords = vNew2;
  132. return;
  133. }
  134. // ------------------------------------------------------------------------------------------------
  135. void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
  136. MaterialHelper& mat)
  137. {
  138. // NOTE: Pass the background image to the viewer by bypassing the
  139. // material system. This is an evil hack, never do it again!
  140. if (0 != this->mBackgroundImage.length() && this->bHasBG)
  141. {
  142. aiString tex;
  143. tex.Set( this->mBackgroundImage);
  144. mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
  145. // be sure this is only done for the first material
  146. this->mBackgroundImage = std::string("");
  147. }
  148. // At first add the base ambient color of the
  149. // scene to the material
  150. oldMat.mAmbient.r += this->mClrAmbient.r;
  151. oldMat.mAmbient.g += this->mClrAmbient.g;
  152. oldMat.mAmbient.b += this->mClrAmbient.b;
  153. aiString name;
  154. name.Set( oldMat.mName);
  155. mat.AddProperty( &name, AI_MATKEY_NAME);
  156. // material colors
  157. mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
  158. mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  159. mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
  160. mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
  161. mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  162. // opacity
  163. mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
  164. // bump height scaling
  165. mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
  166. // shading mode
  167. aiShadingMode eShading = aiShadingMode_NoShading;
  168. switch (oldMat.mShading)
  169. {
  170. case Dot3DS::Dot3DSFile::Flat:
  171. eShading = aiShadingMode_Flat; break;
  172. case Dot3DS::Dot3DSFile::Phong :
  173. eShading = aiShadingMode_Phong; break;
  174. // I don't know what "Wire" shading should be,
  175. // assume it is simple lambertian diffuse (L dot N) shading
  176. case Dot3DS::Dot3DSFile::Wire:
  177. case Dot3DS::Dot3DSFile::Gouraud:
  178. eShading = aiShadingMode_Gouraud; break;
  179. // assume cook-torrance shading for metals.
  180. // NOTE: I assume the real shader inside 3ds max is an anisotropic
  181. // Phong-Blinn shader, but this is a good approximation too
  182. case Dot3DS::Dot3DSFile::Metal :
  183. eShading = aiShadingMode_CookTorrance; break;
  184. }
  185. mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
  186. // texture, if there is one
  187. if( oldMat.sTexDiffuse.mMapName.length() > 0)
  188. {
  189. aiString tex;
  190. tex.Set( oldMat.sTexDiffuse.mMapName);
  191. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
  192. mat.AddProperty<float>( &oldMat.sTexDiffuse.mTextureBlend, 1, AI_MATKEY_TEXBLEND_DIFFUSE(0));
  193. }
  194. if( oldMat.sTexSpecular.mMapName.length() > 0)
  195. {
  196. aiString tex;
  197. tex.Set( oldMat.sTexSpecular.mMapName);
  198. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(0));
  199. mat.AddProperty<float>( &oldMat.sTexSpecular.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SPECULAR(0));
  200. }
  201. if( oldMat.sTexOpacity.mMapName.length() > 0)
  202. {
  203. aiString tex;
  204. tex.Set( oldMat.sTexOpacity.mMapName);
  205. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY(0));
  206. mat.AddProperty<float>( &oldMat.sTexOpacity.mTextureBlend, 1,AI_MATKEY_TEXBLEND_OPACITY(0));
  207. }
  208. if( oldMat.sTexEmissive.mMapName.length() > 0)
  209. {
  210. aiString tex;
  211. tex.Set( oldMat.sTexEmissive.mMapName);
  212. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(0));
  213. mat.AddProperty<float>( &oldMat.sTexEmissive.mTextureBlend, 1, AI_MATKEY_TEXBLEND_EMISSIVE(0));
  214. }
  215. if( oldMat.sTexBump.mMapName.length() > 0)
  216. {
  217. aiString tex;
  218. tex.Set( oldMat.sTexBump.mMapName);
  219. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_BUMP(0));
  220. mat.AddProperty<float>( &oldMat.sTexBump.mTextureBlend, 1, AI_MATKEY_TEXBLEND_BUMP(0));
  221. }
  222. if( oldMat.sTexShininess.mMapName.length() > 0)
  223. {
  224. aiString tex;
  225. tex.Set( oldMat.sTexShininess.mMapName);
  226. mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SHININESS(0));
  227. mat.AddProperty<float>( &oldMat.sTexBump.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SHININESS(0));
  228. }
  229. // store the name of the material itself, too
  230. if( oldMat.mName.length() > 0)
  231. {
  232. aiString tex;
  233. tex.Set( oldMat.mName);
  234. mat.AddProperty( &tex, AI_MATKEY_NAME);
  235. }
  236. return;
  237. }
  238. // ------------------------------------------------------------------------------------------------
  239. void SetupMatUVSrc (aiMaterial* pcMat, const Dot3DS::Material* pcMatIn)
  240. {
  241. MaterialHelper* pcHelper = (MaterialHelper*)pcMat;
  242. pcHelper->AddProperty<int>(&pcMatIn->sTexDiffuse.iUVSrc,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
  243. pcHelper->AddProperty<int>(&pcMatIn->sTexSpecular.iUVSrc,1,AI_MATKEY_UVWSRC_SPECULAR(0));
  244. pcHelper->AddProperty<int>(&pcMatIn->sTexEmissive.iUVSrc,1,AI_MATKEY_UVWSRC_EMISSIVE(0));
  245. pcHelper->AddProperty<int>(&pcMatIn->sTexBump.iUVSrc,1,AI_MATKEY_UVWSRC_BUMP(0));
  246. pcHelper->AddProperty<int>(&pcMatIn->sTexShininess.iUVSrc,1,AI_MATKEY_UVWSRC_SHININESS(0));
  247. pcHelper->AddProperty<int>(&pcMatIn->sTexOpacity.iUVSrc,1,AI_MATKEY_UVWSRC_OPACITY(0));
  248. }
  249. // ------------------------------------------------------------------------------------------------
  250. void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
  251. {
  252. std::vector<aiMesh*> avOutMeshes;
  253. avOutMeshes.reserve(this->mScene->mMeshes.size() * 2);
  254. unsigned int iFaceCnt = 0;
  255. // we need to split all meshes by their materials
  256. for (std::vector<Dot3DS::Mesh>::iterator
  257. i = this->mScene->mMeshes.begin();
  258. i != this->mScene->mMeshes.end();++i)
  259. {
  260. std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[
  261. this->mScene->mMaterials.size()];
  262. unsigned int iNum = 0;
  263. for (std::vector<unsigned int>::const_iterator
  264. a = (*i).mFaceMaterials.begin();
  265. a != (*i).mFaceMaterials.end();++a,++iNum)
  266. {
  267. // check range
  268. if ((*a) >= this->mScene->mMaterials.size())
  269. {
  270. // use the last material instead
  271. aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum);
  272. }
  273. else aiSplit[*a].push_back(iNum);
  274. }
  275. // now generate submeshes
  276. #if 0
  277. bool bFirst = true;
  278. #endif
  279. for (unsigned int p = 0; p < this->mScene->mMaterials.size();++p)
  280. {
  281. if (aiSplit[p].size() != 0)
  282. {
  283. aiMesh* p_pcOut = new aiMesh();
  284. // be sure to setup the correct material index
  285. p_pcOut->mMaterialIndex = p;
  286. // use the color data as temporary storage
  287. p_pcOut->mColors[0] = (aiColor4D*)new std::string((*i).mName);
  288. avOutMeshes.push_back(p_pcOut);
  289. #if 0
  290. if (bFirst)
  291. {
  292. p_pcOut->mColors[1] = (aiColor4D*)new aiMatrix4x4();
  293. *((aiMatrix4x4*)p_pcOut->mColors[1]) = (*i).mMat;
  294. bFirst = false;
  295. }
  296. #endif
  297. // convert vertices
  298. p_pcOut->mNumVertices = aiSplit[p].size()*3;
  299. p_pcOut->mNumFaces = aiSplit[p].size();
  300. iFaceCnt += p_pcOut->mNumFaces;
  301. if (p_pcOut->mNumVertices != 0)
  302. {
  303. p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
  304. p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices];
  305. unsigned int iBase = 0;
  306. p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
  307. for (unsigned int q = 0; q < aiSplit[p].size();++q)
  308. {
  309. unsigned int iIndex = aiSplit[p][q];
  310. p_pcOut->mFaces[q].mIndices = new unsigned int[3];
  311. p_pcOut->mFaces[q].mNumIndices = 3;
  312. p_pcOut->mFaces[q].mIndices[0] = iBase;
  313. p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].i1];
  314. p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].i1];
  315. p_pcOut->mFaces[q].mIndices[1] = iBase;
  316. p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].i2];
  317. p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].i2];
  318. p_pcOut->mFaces[q].mIndices[2] = iBase;
  319. p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].i3];
  320. p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].i3];
  321. }
  322. }
  323. // convert texture coordinates
  324. if ((*i).mTexCoords.size() != 0)
  325. {
  326. p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices];
  327. unsigned int iBase = 0;
  328. for (unsigned int q = 0; q < aiSplit[p].size();++q)
  329. {
  330. unsigned int iIndex2 = aiSplit[p][q];
  331. unsigned int iIndex = (*i).mFaces[iIndex2].i1;
  332. aiVector2D& pc = (*i).mTexCoords[iIndex];
  333. p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc.x,pc.y,0.0f);
  334. iIndex = (*i).mFaces[iIndex2].i2;
  335. pc = (*i).mTexCoords[iIndex];
  336. p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc.x,pc.y,0.0f);
  337. iIndex = (*i).mFaces[iIndex2].i3;
  338. pc = (*i).mTexCoords[iIndex];
  339. p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc.x,pc.y,0.0f);
  340. }
  341. // apply texture coordinate scalings
  342. this->BakeScaleNOffset ( p_pcOut, &this->mScene->mMaterials[
  343. p_pcOut->mMaterialIndex] );
  344. // setup bitflags to indicate which texture coordinate
  345. // channels are used
  346. p_pcOut->mNumUVComponents[0] = 2;
  347. if (p_pcOut->HasTextureCoords(1))
  348. p_pcOut->mNumUVComponents[1] = 2;
  349. if (p_pcOut->HasTextureCoords(2))
  350. p_pcOut->mNumUVComponents[2] = 2;
  351. if (p_pcOut->HasTextureCoords(3))
  352. p_pcOut->mNumUVComponents[3] = 2;
  353. }
  354. }
  355. }
  356. delete[] aiSplit;
  357. }
  358. pcOut->mNumMeshes = avOutMeshes.size();
  359. pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
  360. for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
  361. {
  362. pcOut->mMeshes[a] = avOutMeshes[a];
  363. }
  364. if (0 == iFaceCnt)
  365. {
  366. throw new ImportErrorException("No faces loaded. The mesh is empty");
  367. }
  368. // for each material in the scene we need to setup the UV source
  369. // set for each texture
  370. for (unsigned int a = 0; a < pcOut->mNumMaterials;++a)
  371. {
  372. SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
  373. }
  374. return;
  375. }
  376. // ------------------------------------------------------------------------------------------------
  377. void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* pcIn)
  378. {
  379. // find the corresponding mesh indices
  380. std::vector<unsigned int> iArray;
  381. if (pcIn->mName != "$$$DUMMY")
  382. {
  383. for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
  384. {
  385. if (0 == ASSIMP_stricmp(pcIn->mName.c_str(),
  386. ((std::string*)pcSOut->mMeshes[a]->mColors[0])->c_str()))
  387. {
  388. iArray.push_back(a);
  389. }
  390. }
  391. }
  392. pcOut->mName.Set(pcIn->mName);
  393. pcOut->mNumMeshes = iArray.size();
  394. pcOut->mMeshes = new unsigned int[iArray.size()];
  395. for (unsigned int i = 0;i < iArray.size();++i)
  396. {
  397. const unsigned int iIndex = iArray[i];
  398. #if 0
  399. if (NULL != pcSOut->mMeshes[iIndex]->mColors[1])
  400. {
  401. pcOut->mTransformation = *((aiMatrix4x4*)
  402. (pcSOut->mMeshes[iIndex]->mColors[1]));
  403. delete (aiMatrix4x4*)pcSOut->mMeshes[iIndex]->mColors[1];
  404. pcSOut->mMeshes[iIndex]->mColors[1] = NULL;
  405. }
  406. #endif
  407. pcOut->mMeshes[i] = iIndex;
  408. }
  409. // NOTE: Not necessary. We can use the given transformation matrix.
  410. // However, we'd need it if we wanted to implement keyframe animation
  411. #if 0
  412. // build the scaling matrix. Toggle y and z axis
  413. aiMatrix4x4 mS;
  414. mS.a1 = pcIn->vScaling.x;
  415. mS.b2 = pcIn->vScaling.z;
  416. mS.c3 = pcIn->vScaling.y;
  417. // build the translation matrix. Toggle y and z axis
  418. aiMatrix4x4 mT;
  419. mT.a4 = pcIn->vPosition.x;
  420. mT.b4 = pcIn->vPosition.z;
  421. mT.c4 = pcIn->vPosition.y;
  422. // build the pivot matrix. Toggle y and z axis
  423. aiMatrix4x4 mP;
  424. mP.a4 = pcIn->vPivot.x;
  425. mP.b4 = pcIn->vPivot.z;
  426. mP.c4 = pcIn->vPivot.y;
  427. #endif
  428. pcOut->mTransformation = aiMatrix4x4(); // mT * pcIn->mRotation * mS * mP * pcOut->mTransformation.Inverse();
  429. pcOut->mNumChildren = pcIn->mChildren.size();
  430. pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
  431. for (unsigned int i = 0; i < pcIn->mChildren.size();++i)
  432. {
  433. pcOut->mChildren[i] = new aiNode();
  434. pcOut->mChildren[i]->mParent = pcOut;
  435. AddNodeToGraph(pcSOut,pcOut->mChildren[i],
  436. pcIn->mChildren[i]);
  437. }
  438. return;
  439. }
  440. // ------------------------------------------------------------------------------------------------
  441. inline bool HasUVTransform(const Dot3DS::Texture& rcIn)
  442. {
  443. return (0.0f != rcIn.mOffsetU ||
  444. 0.0f != rcIn.mOffsetV ||
  445. 1.0f != rcIn.mScaleU ||
  446. 1.0f != rcIn.mScaleV ||
  447. 0.0f != rcIn.mRotation);
  448. }
  449. // ------------------------------------------------------------------------------------------------
  450. void Dot3DSImporter::ApplyScaleNOffset()
  451. {
  452. unsigned int iNum = 0;
  453. for (std::vector<Dot3DS::Material>::iterator
  454. i = this->mScene->mMaterials.begin();
  455. i != this->mScene->mMaterials.end();++i,++iNum)
  456. {
  457. unsigned int iCnt = 0;
  458. Dot3DS::Texture* pcTexture = NULL;
  459. if (HasUVTransform((*i).sTexDiffuse))
  460. {
  461. (*i).sTexDiffuse.bPrivate = true;
  462. pcTexture = &(*i).sTexDiffuse;
  463. ++iCnt;
  464. }
  465. if (HasUVTransform((*i).sTexSpecular))
  466. {
  467. (*i).sTexSpecular.bPrivate = true;
  468. pcTexture = &(*i).sTexSpecular;
  469. ++iCnt;
  470. }
  471. if (HasUVTransform((*i).sTexOpacity))
  472. {
  473. (*i).sTexOpacity.bPrivate = true;
  474. pcTexture = &(*i).sTexOpacity;
  475. ++iCnt;
  476. }
  477. if (HasUVTransform((*i).sTexEmissive))
  478. {
  479. (*i).sTexEmissive.bPrivate = true;
  480. pcTexture = &(*i).sTexEmissive;
  481. ++iCnt;
  482. }
  483. if (HasUVTransform((*i).sTexBump))
  484. {
  485. (*i).sTexBump.bPrivate = true;
  486. pcTexture = &(*i).sTexBump;
  487. ++iCnt;
  488. }
  489. if (HasUVTransform((*i).sTexShininess))
  490. {
  491. (*i).sTexShininess.bPrivate = true;
  492. pcTexture = &(*i).sTexShininess;
  493. ++iCnt;
  494. }
  495. if (0 != iCnt)
  496. {
  497. // if only one texture needs scaling/offset operations
  498. // we can apply them directly to the first texture
  499. // coordinate sets of all meshes referencing *this* material
  500. // However, we can't do it now. We need to wait until
  501. // everything is sorted by materials.
  502. if (1 == iCnt)
  503. {
  504. (*i).iBakeUVTransform = 1;
  505. (*i).pcSingleTexture = pcTexture;
  506. }
  507. // we will need to generate a separate new texture channel
  508. // for each texture.
  509. // However, we can't do it now. We need to wait until
  510. // everything is sorted by materials.
  511. else (*i).iBakeUVTransform = 2;
  512. }
  513. }
  514. }
  515. // ------------------------------------------------------------------------------------------------
  516. struct STransformVecInfo
  517. {
  518. float fScaleU;
  519. float fScaleV;
  520. float fOffsetU;
  521. float fOffsetV;
  522. float fRotation;
  523. std::vector<Dot3DS::Texture*> pcTextures;
  524. };
  525. // ------------------------------------------------------------------------------------------------
  526. void AddToList(std::vector<STransformVecInfo>& rasVec,Dot3DS::Texture* pcTex)
  527. {
  528. if (0 == pcTex->mMapName.length())return;
  529. for (std::vector<STransformVecInfo>::iterator
  530. i = rasVec.begin();
  531. i != rasVec.end();++i)
  532. {
  533. if ((*i).fOffsetU == pcTex->mOffsetU &&
  534. (*i).fOffsetV == pcTex->mOffsetV &&
  535. (*i).fScaleU == pcTex->mScaleU &&
  536. (*i).fScaleV == pcTex->mScaleV &&
  537. (*i).fRotation == pcTex->mRotation)
  538. {
  539. (*i).pcTextures.push_back(pcTex);
  540. return;
  541. }
  542. }
  543. STransformVecInfo sInfo;
  544. sInfo.fScaleU = pcTex->mScaleU;
  545. sInfo.fScaleV = pcTex->mScaleV;
  546. sInfo.fOffsetU = pcTex->mOffsetU;
  547. sInfo.fOffsetV = pcTex->mOffsetV;
  548. sInfo.fRotation = pcTex->mRotation;
  549. sInfo.pcTextures.push_back(pcTex);
  550. rasVec.push_back(sInfo);
  551. }
  552. // ------------------------------------------------------------------------------------------------
  553. void Dot3DSImporter::BakeScaleNOffset(
  554. aiMesh* pcMesh, Dot3DS::Material* pcSrc)
  555. {
  556. if (!pcMesh->mTextureCoords[0])return;
  557. if (1 == pcSrc->iBakeUVTransform)
  558. {
  559. if (0.0f == pcSrc->pcSingleTexture->mRotation)
  560. {
  561. for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
  562. {
  563. pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU;
  564. pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV;
  565. pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU;
  566. pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV;
  567. }
  568. }
  569. else
  570. {
  571. const float fSin = sinf(pcSrc->pcSingleTexture->mRotation);
  572. const float fCos = cosf(pcSrc->pcSingleTexture->mRotation);
  573. for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
  574. {
  575. pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU;
  576. pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV;
  577. pcMesh->mTextureCoords[0][i].x *= fCos;
  578. pcMesh->mTextureCoords[0][i].y *= fSin;
  579. pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU;
  580. pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV;
  581. }
  582. }
  583. }
  584. else if (2 == pcSrc->iBakeUVTransform)
  585. {
  586. // now we need to find all textures in the material
  587. // which require scaling/offset operations
  588. std::vector<STransformVecInfo> sOps;
  589. AddToList(sOps,&pcSrc->sTexDiffuse);
  590. AddToList(sOps,&pcSrc->sTexSpecular);
  591. AddToList(sOps,&pcSrc->sTexEmissive);
  592. AddToList(sOps,&pcSrc->sTexOpacity);
  593. AddToList(sOps,&pcSrc->sTexBump);
  594. AddToList(sOps,&pcSrc->sTexShininess);
  595. const aiVector3D* _pvBase;
  596. if (0.0f == sOps[0].fOffsetU && 0.0f == sOps[0].fOffsetV &&
  597. 1.0f == sOps[0].fScaleU && 1.0f == sOps[0].fScaleV &&
  598. 0.0f == sOps[0].fRotation)
  599. {
  600. // we'll have an unmodified set, so we can use *this* one
  601. _pvBase = pcMesh->mTextureCoords[0];
  602. }
  603. else
  604. {
  605. _pvBase = new aiVector3D[pcMesh->mNumVertices];
  606. memcpy(const_cast<aiVector3D*>(_pvBase),pcMesh->mTextureCoords[0],
  607. pcMesh->mNumVertices * sizeof(aiVector3D));
  608. }
  609. unsigned int iCnt = 0;
  610. for (std::vector<STransformVecInfo>::iterator
  611. i = sOps.begin();
  612. i != sOps.end();++i,++iCnt)
  613. {
  614. if (!pcMesh->mTextureCoords[iCnt])
  615. {
  616. pcMesh->mTextureCoords[iCnt] = new aiVector3D[pcMesh->mNumVertices];
  617. }
  618. // more than 4 UV texture channels are not available
  619. if (iCnt > 3)
  620. {
  621. for (std::vector<Dot3DS::Texture*>::iterator
  622. a = (*i).pcTextures.begin();
  623. a != (*i).pcTextures.end();++a)
  624. {
  625. (*a)->iUVSrc = 0;
  626. }
  627. continue;
  628. }
  629. const aiVector3D* pvBase = _pvBase;
  630. if (0.0f == (*i).fRotation)
  631. {
  632. for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
  633. {
  634. pcMesh->mTextureCoords[iCnt][n].x = pvBase->x * (*i).fScaleU;
  635. pcMesh->mTextureCoords[iCnt][n].y = pvBase->y * (*i).fScaleV;
  636. pcMesh->mTextureCoords[iCnt][n].x += (*i).fOffsetU;
  637. pcMesh->mTextureCoords[iCnt][n].y += (*i).fOffsetV;
  638. pvBase++;
  639. }
  640. }
  641. else
  642. {
  643. const float fSin = sinf((*i).fRotation);
  644. const float fCos = cosf((*i).fRotation);
  645. for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
  646. {
  647. pcMesh->mTextureCoords[iCnt][n].x = pvBase->x * (*i).fScaleU;
  648. pcMesh->mTextureCoords[iCnt][n].y = pvBase->y * (*i).fScaleV;
  649. pcMesh->mTextureCoords[iCnt][n].x *= fCos;
  650. pcMesh->mTextureCoords[iCnt][n].y *= fSin;
  651. pcMesh->mTextureCoords[iCnt][n].x += (*i).fOffsetU;
  652. pcMesh->mTextureCoords[iCnt][n].y += (*i).fOffsetV;
  653. pvBase++;
  654. }
  655. }
  656. // setup UV source
  657. for (std::vector<Dot3DS::Texture*>::iterator
  658. a = (*i).pcTextures.begin();
  659. a != (*i).pcTextures.end();++a)
  660. {
  661. (*a)->iUVSrc = iCnt;
  662. }
  663. }
  664. // release temporary storage
  665. if (_pvBase != pcMesh->mTextureCoords[0])
  666. delete[] _pvBase;
  667. }
  668. }
  669. // ------------------------------------------------------------------------------------------------
  670. void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut)
  671. {
  672. pcOut->mRootNode = new aiNode();
  673. if (0 == this->mRootNode->mChildren.size())
  674. {
  675. // seems the file has not even a hierarchy.
  676. // generate a flat hiearachy which looks like this:
  677. //
  678. // ROOT_NODE
  679. // |
  680. // ----------------------------------------
  681. // | | | |
  682. // MESH_0 MESH_1 MESH_2 ... MESH_N
  683. //
  684. unsigned int iCnt = 0;
  685. pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes;
  686. pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mNumMeshes ];
  687. for (unsigned int i = 0; i < pcOut->mNumMeshes;++i)
  688. {
  689. aiNode* pcNode = new aiNode();
  690. pcNode->mParent = pcOut->mRootNode;
  691. pcNode->mNumChildren = 0;
  692. pcNode->mChildren = 0;
  693. pcNode->mMeshes = new unsigned int[1];
  694. pcNode->mMeshes[0] = i;
  695. pcNode->mNumMeshes = 1;
  696. pcNode->mName.Set("UNNAMED");
  697. // add the new child to the parent node
  698. pcOut->mRootNode->mChildren[i] = pcNode;
  699. }
  700. }
  701. else this->AddNodeToGraph(pcOut, pcOut->mRootNode, this->mRootNode);
  702. for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
  703. {
  704. delete (std::string*)pcOut->mMeshes[a]->mColors[0];
  705. pcOut->mMeshes[a]->mColors[0] = NULL;
  706. // may be NULL
  707. delete (aiMatrix4x4*)pcOut->mMeshes[a]->mColors[1];
  708. pcOut->mMeshes[a]->mColors[1] = NULL;
  709. }
  710. }
  711. // ------------------------------------------------------------------------------------------------
  712. void Dot3DSImporter::ConvertScene(aiScene* pcOut)
  713. {
  714. pcOut->mNumMaterials = this->mScene->mMaterials.size();
  715. pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials];
  716. for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
  717. {
  718. MaterialHelper* pcNew = new MaterialHelper();
  719. this->ConvertMaterial(this->mScene->mMaterials[i],*pcNew);
  720. pcOut->mMaterials[i] = pcNew;
  721. }
  722. this->ConvertMeshes(pcOut);
  723. return;
  724. }
  725. // ------------------------------------------------------------------------------------------------
  726. void Dot3DSImporter::GenTexCoord (Dot3DS::Texture* pcTexture,
  727. const std::vector<aiVector2D>& p_vIn,
  728. std::vector<aiVector2D>& p_vOut)
  729. {
  730. p_vOut.resize(p_vIn.size());
  731. std::vector<aiVector2D>::const_iterator i = p_vIn.begin();
  732. std::vector<aiVector2D>::iterator a = p_vOut.begin();
  733. for(;i != p_vOut.end();++i,++a)
  734. {
  735. // TODO: Find out in which order 3ds max is performing
  736. // scaling and translation. However it seems reasonable to
  737. // scale first.
  738. //
  739. // TODO: http://www.jalix.org/ressources/graphics/3DS/_specifications/3ds-0.1.htm
  740. // says it is not u and v scale but 1/u and 1/v scale. Other sources
  741. // tell different things. Believe this one, the author seems to be funny
  742. // or drunken or both ;-)
  743. (*a) = (*i);
  744. (*a).x /= pcTexture->mScaleU;
  745. (*a).y /= pcTexture->mScaleV;
  746. (*a).x += pcTexture->mOffsetU;
  747. (*a).y += pcTexture->mOffsetV;
  748. }
  749. return;
  750. }