MDLLoader.cpp 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765
  1. /*
  2. ---------------------------------------------------------------------------
  3. Free 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 MDL importer class */
  35. #include "MaterialSystem.h"
  36. #include "MDLLoader.h"
  37. #include "MDLDefaultColorMap.h"
  38. #include "DefaultLogger.h"
  39. #include "../include/IOStream.h"
  40. #include "../include/IOSystem.h"
  41. #include "../include/aiMesh.h"
  42. #include "../include/aiScene.h"
  43. #include "../include/aiAssert.h"
  44. #include <boost/scoped_ptr.hpp>
  45. using namespace Assimp;
  46. extern float g_avNormals[162][3];
  47. // ------------------------------------------------------------------------------------------------
  48. inline bool is_qnan(float p_fIn)
  49. {
  50. // NOTE: Comparison against qnan is generally problematic
  51. // because qnan == qnan is false AFAIK
  52. union FTOINT
  53. {
  54. float fFloat;
  55. int32_t iInt;
  56. } one, two;
  57. one.fFloat = std::numeric_limits<float>::quiet_NaN();
  58. two.fFloat = p_fIn;
  59. return (one.iInt == two.iInt);
  60. }
  61. // ------------------------------------------------------------------------------------------------
  62. inline bool is_not_qnan(float p_fIn)
  63. {
  64. return !is_qnan(p_fIn);
  65. }
  66. // ------------------------------------------------------------------------------------------------
  67. // Constructor to be privately used by Importer
  68. MDLImporter::MDLImporter()
  69. {
  70. // nothing to do here
  71. }
  72. // ------------------------------------------------------------------------------------------------
  73. // Destructor, private as well
  74. MDLImporter::~MDLImporter()
  75. {
  76. // nothing to do here
  77. }
  78. // ------------------------------------------------------------------------------------------------
  79. // Returns whether the class can handle the format of the given file.
  80. bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
  81. {
  82. // simple check of file extension is enough for the moment
  83. std::string::size_type pos = pFile.find_last_of('.');
  84. // no file extension - can't read
  85. if( pos == std::string::npos)
  86. return false;
  87. std::string extension = pFile.substr( pos);
  88. if (extension.length() < 4)return false;
  89. if (extension[0] != '.')return false;
  90. if (extension[1] != 'm' && extension[1] != 'M')return false;
  91. if (extension[2] != 'd' && extension[2] != 'D')return false;
  92. if (extension[3] != 'l' && extension[3] != 'L')return false;
  93. return true;
  94. }
  95. // ------------------------------------------------------------------------------------------------
  96. // Imports the given file into the given scene structure.
  97. void MDLImporter::InternReadFile(
  98. const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
  99. {
  100. boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
  101. // Check whether we can read from the file
  102. if( file.get() == NULL)
  103. {
  104. throw new ImportErrorException( "Failed to open MDL file " + pFile + ".");
  105. }
  106. // check whether the ply file is large enough to contain
  107. // at least the file header
  108. size_t fileSize = file->FileSize();
  109. if( fileSize < sizeof(MDL::Header))
  110. {
  111. throw new ImportErrorException( ".mdl File is too small.");
  112. }
  113. // allocate storage and copy the contents of the file to a memory buffer
  114. this->pScene = pScene;
  115. this->pIOHandler = pIOHandler;
  116. this->mBuffer = new unsigned char[fileSize+1];
  117. file->Read( (void*)mBuffer, 1, fileSize);
  118. // determine the file subtype and call the appropriate member function
  119. // Original Quake1 format
  120. this->m_pcHeader = (const MDL::Header*)this->mBuffer;
  121. if (AI_MDL_MAGIC_NUMBER_BE == this->m_pcHeader->ident ||
  122. AI_MDL_MAGIC_NUMBER_LE == this->m_pcHeader->ident)
  123. {
  124. this->InternReadFile_Quake1();
  125. }
  126. // GameStudio A4 MDL3 format
  127. else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == this->m_pcHeader->ident ||
  128. AI_MDL_MAGIC_NUMBER_LE_GS4 == this->m_pcHeader->ident)
  129. {
  130. this->iGSFileVersion = 3;
  131. this->InternReadFile_GameStudio();
  132. }
  133. // GameStudio A5+ MDL4 format
  134. else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == this->m_pcHeader->ident ||
  135. AI_MDL_MAGIC_NUMBER_LE_GS5a == this->m_pcHeader->ident)
  136. {
  137. this->iGSFileVersion = 4;
  138. this->InternReadFile_GameStudio();
  139. }
  140. // GameStudio A5+ MDL5 format
  141. else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == this->m_pcHeader->ident ||
  142. AI_MDL_MAGIC_NUMBER_LE_GS5b == this->m_pcHeader->ident)
  143. {
  144. this->iGSFileVersion = 5;
  145. this->InternReadFile_GameStudio();
  146. }
  147. // GameStudio A6+ MDL6 format
  148. else if (AI_MDL_MAGIC_NUMBER_BE_GS6 == this->m_pcHeader->ident ||
  149. AI_MDL_MAGIC_NUMBER_LE_GS6 == this->m_pcHeader->ident)
  150. {
  151. this->iGSFileVersion = 6;
  152. this->InternReadFile_GameStudio();
  153. }
  154. // GameStudio A7 MDL7 format
  155. else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == this->m_pcHeader->ident ||
  156. AI_MDL_MAGIC_NUMBER_LE_GS7 == this->m_pcHeader->ident)
  157. {
  158. this->iGSFileVersion = 7;
  159. this->InternReadFile_GameStudioA7();
  160. }
  161. else
  162. {
  163. // we're definitely unable to load this file
  164. throw new ImportErrorException( "Unknown MDL subformat " + pFile +
  165. ". Magic word is not known");
  166. }
  167. // delete the file buffer
  168. delete[] this->mBuffer;
  169. return;
  170. }
  171. // ------------------------------------------------------------------------------------------------
  172. void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
  173. {
  174. // now try to find the color map in the current directory
  175. IOStream* pcStream = this->pIOHandler->Open("colormap.lmp","rb");
  176. const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
  177. if(pcStream)
  178. {
  179. if (pcStream->FileSize() >= 768)
  180. {
  181. szColorMap = new unsigned char[256*3];
  182. pcStream->Read(const_cast<unsigned char*>(szColorMap),256*3,1);
  183. }
  184. delete pcStream;
  185. pcStream = NULL;
  186. }
  187. *pszColorMap = szColorMap;
  188. return;
  189. }
  190. // ------------------------------------------------------------------------------------------------
  191. void MDLImporter::FreePalette(const unsigned char* szColorMap)
  192. {
  193. if (szColorMap != (const unsigned char*)::g_aclrDefaultColorMap)
  194. {
  195. delete[] szColorMap;
  196. }
  197. return;
  198. }
  199. // ------------------------------------------------------------------------------------------------
  200. void MDLImporter::CreateTextureARGB8(const unsigned char* szData)
  201. {
  202. // allocate a new texture object
  203. aiTexture* pcNew = new aiTexture();
  204. pcNew->mWidth = this->m_pcHeader->skinwidth;
  205. pcNew->mHeight = this->m_pcHeader->skinheight;
  206. pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
  207. const unsigned char* szColorMap;
  208. this->SearchPalette(&szColorMap);
  209. // copy texture data
  210. for (unsigned int i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  211. {
  212. const unsigned char val = szData[i];
  213. const unsigned char* sz = &szColorMap[val*3];
  214. pcNew->pcData[i].a = 0xFF;
  215. pcNew->pcData[i].r = *sz++;
  216. pcNew->pcData[i].g = *sz++;
  217. pcNew->pcData[i].b = *sz;
  218. }
  219. this->FreePalette(szColorMap);
  220. // store the texture
  221. aiTexture** pc = this->pScene->mTextures;
  222. this->pScene->mTextures = new aiTexture*[this->pScene->mNumTextures+1];
  223. for (unsigned int i = 0; i < this->pScene->mNumTextures;++i)
  224. this->pScene->mTextures[i] = pc[i];
  225. this->pScene->mTextures[this->pScene->mNumTextures] = pcNew;
  226. this->pScene->mNumTextures++;
  227. delete[] pc;
  228. return;
  229. }
  230. // ------------------------------------------------------------------------------------------------
  231. void MDLImporter::CreateTextureARGB8_GS4(const unsigned char* szData,
  232. unsigned int iType,
  233. unsigned int* piSkip)
  234. {
  235. ai_assert(NULL != piSkip);
  236. // allocate a new texture object
  237. aiTexture* pcNew = new aiTexture();
  238. pcNew->mWidth = this->m_pcHeader->skinwidth;
  239. pcNew->mHeight = this->m_pcHeader->skinheight;
  240. pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
  241. // 8 Bit paletized. Use Q1 default palette.
  242. if (0 == iType)
  243. {
  244. const unsigned char* szColorMap;
  245. this->SearchPalette(&szColorMap);
  246. // copy texture data
  247. unsigned int i = 0;
  248. for (; i < pcNew->mWidth*pcNew->mHeight;++i)
  249. {
  250. const unsigned char val = szData[i];
  251. const unsigned char* sz = &szColorMap[val*3];
  252. pcNew->pcData[i].a = 0xFF;
  253. pcNew->pcData[i].r = *sz++;
  254. pcNew->pcData[i].g = *sz++;
  255. pcNew->pcData[i].b = *sz;
  256. }
  257. *piSkip = i;
  258. this->FreePalette(szColorMap);
  259. }
  260. // R5G6B5 format
  261. else if (2 == iType)
  262. {
  263. // copy texture data
  264. unsigned int i = 0;
  265. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  266. {
  267. MDL::RGB565 val = ((MDL::RGB565*)szData)[i];
  268. pcNew->pcData[i].a = 0xFF;
  269. pcNew->pcData[i].r = (unsigned char)val.b << 3;
  270. pcNew->pcData[i].g = (unsigned char)val.g << 2;
  271. pcNew->pcData[i].b = (unsigned char)val.r << 3;
  272. }
  273. *piSkip = i * 2;
  274. }
  275. // ARGB4 format
  276. else if (3 == iType)
  277. {
  278. // copy texture data
  279. unsigned int i = 0;
  280. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  281. {
  282. MDL::ARGB4 val = ((MDL::ARGB4*)szData)[i];
  283. pcNew->pcData[i].a = (unsigned char)val.a << 4;
  284. pcNew->pcData[i].r = (unsigned char)val.r << 4;
  285. pcNew->pcData[i].g = (unsigned char)val.g << 4;
  286. pcNew->pcData[i].b = (unsigned char)val.b << 4;
  287. }
  288. *piSkip = i * 2;
  289. }
  290. // store the texture
  291. aiTexture** pc = this->pScene->mTextures;
  292. this->pScene->mTextures = new aiTexture*[this->pScene->mNumTextures+1];
  293. for (unsigned int i = 0; i < this->pScene->mNumTextures;++i)
  294. this->pScene->mTextures[i] = pc[i];
  295. this->pScene->mTextures[this->pScene->mNumTextures] = pcNew;
  296. this->pScene->mNumTextures++;
  297. delete[] pc;
  298. return;
  299. }
  300. // ------------------------------------------------------------------------------------------------
  301. void MDLImporter::ParseTextureColorData(const unsigned char* szData,
  302. unsigned int iType,
  303. unsigned int* piSkip,
  304. aiTexture* pcNew)
  305. {
  306. // allocate storage for the texture image
  307. pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
  308. // R5G6B5 format (with or without MIPs)
  309. if (2 == iType || 10 == iType)
  310. {
  311. // copy texture data
  312. unsigned int i = 0;
  313. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  314. {
  315. MDL::RGB565 val = ((MDL::RGB565*)szData)[i];
  316. pcNew->pcData[i].a = 0xFF;
  317. pcNew->pcData[i].r = (unsigned char)val.b << 3;
  318. pcNew->pcData[i].g = (unsigned char)val.g << 2;
  319. pcNew->pcData[i].b = (unsigned char)val.r << 3;
  320. }
  321. *piSkip = i * 2;
  322. // apply MIP maps
  323. if (10 == iType)
  324. {
  325. *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
  326. }
  327. }
  328. // ARGB4 format (with or without MIPs)
  329. else if (3 == iType || 11 == iType)
  330. {
  331. // copy texture data
  332. unsigned int i = 0;
  333. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  334. {
  335. MDL::ARGB4 val = ((MDL::ARGB4*)szData)[i];
  336. pcNew->pcData[i].a = (unsigned char)val.a << 4;
  337. pcNew->pcData[i].r = (unsigned char)val.r << 4;
  338. pcNew->pcData[i].g = (unsigned char)val.g << 4;
  339. pcNew->pcData[i].b = (unsigned char)val.b << 4;
  340. }
  341. *piSkip = i * 2;
  342. // apply MIP maps
  343. if (11 == iType)
  344. {
  345. *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1;
  346. }
  347. }
  348. // RGB8 format (with or without MIPs)
  349. else if (4 == iType || 12 == iType)
  350. {
  351. // copy texture data
  352. unsigned int i = 0;
  353. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  354. {
  355. const unsigned char* _szData = &szData[i*3];
  356. pcNew->pcData[i].a = 0xFF;
  357. pcNew->pcData[i].b = *_szData++;
  358. pcNew->pcData[i].g = *_szData++;
  359. pcNew->pcData[i].r = *_szData;
  360. }
  361. // apply MIP maps
  362. *piSkip = i * 3;
  363. if (12 == iType)
  364. {
  365. *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) *3;
  366. }
  367. }
  368. // ARGB8 format (with ir without MIPs)
  369. else if (5 == iType || 13 == iType)
  370. {
  371. // copy texture data
  372. unsigned int i = 0;
  373. for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i)
  374. {
  375. const unsigned char* _szData = &szData[i*4];
  376. pcNew->pcData[i].b = *_szData++;
  377. pcNew->pcData[i].g = *_szData++;
  378. pcNew->pcData[i].r = *_szData++;
  379. pcNew->pcData[i].a = *_szData;
  380. }
  381. // apply MIP maps
  382. *piSkip = i << 2;
  383. if (13 == iType)
  384. {
  385. *piSkip += (i + (i >> 2) + (i >> 4) + (i >> 6)) << 2;
  386. }
  387. }
  388. // palletized 8 bit texture. As for Quake 1
  389. else if (0 == iType)
  390. {
  391. const unsigned char* szColorMap;
  392. this->SearchPalette(&szColorMap);
  393. // copy texture data
  394. unsigned int i = 0;
  395. for (; i < pcNew->mWidth*pcNew->mHeight;++i)
  396. {
  397. const unsigned char val = szData[i];
  398. const unsigned char* sz = &szColorMap[val*3];
  399. pcNew->pcData[i].a = 0xFF;
  400. pcNew->pcData[i].r = *sz++;
  401. pcNew->pcData[i].g = *sz++;
  402. pcNew->pcData[i].b = *sz;
  403. }
  404. *piSkip = i;
  405. this->FreePalette(szColorMap);
  406. }
  407. return;
  408. }
  409. // ------------------------------------------------------------------------------------------------
  410. void MDLImporter::CreateTextureARGB8_GS5(const unsigned char* szData,
  411. unsigned int iType,
  412. unsigned int* piSkip)
  413. {
  414. ai_assert(NULL != piSkip);
  415. // allocate a new texture object
  416. aiTexture* pcNew = new aiTexture();
  417. // first read the size of the texture
  418. pcNew->mWidth = *((uint32_t*)szData);
  419. szData += sizeof(uint32_t);
  420. pcNew->mHeight = *((uint32_t*)szData);
  421. szData += sizeof(uint32_t);
  422. if (6 == iType)
  423. {
  424. // this is a compressed texture in DDS format
  425. *piSkip = pcNew->mWidth;
  426. pcNew->mHeight = 0;
  427. pcNew->achFormatHint[0] = 'd';
  428. pcNew->achFormatHint[1] = 'd';
  429. pcNew->achFormatHint[2] = 's';
  430. pcNew->achFormatHint[3] = '\0';
  431. pcNew->pcData = (aiTexel*) new unsigned char[pcNew->mWidth];
  432. memcpy(pcNew->pcData,szData,pcNew->mWidth);
  433. }
  434. else
  435. {
  436. // parse the color data of the texture
  437. this->ParseTextureColorData(szData,iType,
  438. piSkip,pcNew);
  439. }
  440. *piSkip += sizeof(uint32_t) * 2;
  441. // store the texture
  442. aiTexture** pc = this->pScene->mTextures;
  443. this->pScene->mTextures = new aiTexture*[this->pScene->mNumTextures+1];
  444. for (unsigned int i = 0; i < this->pScene->mNumTextures;++i)
  445. this->pScene->mTextures[i] = pc[i];
  446. this->pScene->mTextures[this->pScene->mNumTextures] = pcNew;
  447. this->pScene->mNumTextures++;
  448. delete[] pc;
  449. return;
  450. }
  451. // ------------------------------------------------------------------------------------------------
  452. void MDLImporter::InternReadFile_Quake1( )
  453. {
  454. ai_assert(NULL != pScene);
  455. if(0 == this->m_pcHeader->num_frames)
  456. {
  457. throw new ImportErrorException( "[Quake 1 MDL] No frames found");
  458. }
  459. // allocate enough storage to hold all vertices and triangles
  460. aiMesh* pcMesh = new aiMesh();
  461. // current cursor position in the file
  462. const unsigned char* szCurrent = (const unsigned char*)(this->m_pcHeader+1);
  463. // need to read all textures
  464. for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->num_skins;++i)
  465. {
  466. union{const MDL::Skin* pcSkin;const MDL::GroupSkin* pcGroupSkin;};
  467. pcSkin = (const MDL::Skin*)szCurrent;
  468. if (0 == pcSkin->group)
  469. {
  470. // create one output image
  471. this->CreateTextureARGB8((unsigned char*)pcSkin + sizeof(uint32_t));
  472. // need to skip one image
  473. szCurrent += this->m_pcHeader->skinheight * this->m_pcHeader->skinwidth+ sizeof(uint32_t);
  474. }
  475. else
  476. {
  477. // need to skip multiple images
  478. const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb;
  479. szCurrent += sizeof(uint32_t) * 2;
  480. if (0 != iNumImages)
  481. {
  482. // however, create only one output image (the first)
  483. this->CreateTextureARGB8(szCurrent + iNumImages * sizeof(float));
  484. for (unsigned int a = 0; a < iNumImages;++a)
  485. {
  486. szCurrent += this->m_pcHeader->skinheight * this->m_pcHeader->skinwidth +
  487. sizeof(float);
  488. }
  489. }
  490. }
  491. }
  492. // get a pointer to the texture coordinates
  493. const MDL::TexCoord* pcTexCoords = (const MDL::TexCoord*)szCurrent;
  494. szCurrent += sizeof(MDL::TexCoord) * this->m_pcHeader->num_verts;
  495. // get a pointer to the triangles
  496. const MDL::Triangle* pcTriangles = (const MDL::Triangle*)szCurrent;
  497. szCurrent += sizeof(MDL::Triangle) * this->m_pcHeader->num_tris;
  498. // now get a pointer to the first frame in the file
  499. const MDL::Frame* pcFrames = (const MDL::Frame*)szCurrent;
  500. const MDL::SimpleFrame* pcFirstFrame;
  501. if (0 == pcFrames->type)
  502. {
  503. // get address of single frame
  504. pcFirstFrame = &pcFrames->frame;
  505. }
  506. else
  507. {
  508. // get the first frame in the group
  509. const MDL::GroupFrame* pcFrames2 = (const MDL::GroupFrame*)pcFrames;
  510. pcFirstFrame = (const MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
  511. }
  512. const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) +
  513. sizeof(pcFirstFrame->name));
  514. pcMesh->mNumVertices = this->m_pcHeader->num_tris * 3;
  515. pcMesh->mNumFaces = this->m_pcHeader->num_tris;
  516. pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  517. pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  518. pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  519. pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  520. pcMesh->mNumUVComponents[0] = 2;
  521. // there won't be more than one mesh inside the file
  522. pScene->mNumMaterials = 1;
  523. pScene->mRootNode = new aiNode();
  524. pScene->mRootNode->mNumMeshes = 1;
  525. pScene->mRootNode->mMeshes = new unsigned int[1];
  526. pScene->mRootNode->mMeshes[0] = 0;
  527. pScene->mMaterials = new aiMaterial*[1];
  528. pScene->mMaterials[0] = new MaterialHelper();
  529. pScene->mNumMeshes = 1;
  530. pScene->mMeshes = new aiMesh*[1];
  531. pScene->mMeshes[0] = pcMesh;
  532. // setup the material properties
  533. const int iMode = (int)aiShadingMode_Gouraud;
  534. MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
  535. pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  536. aiColor3D clr;
  537. clr.b = clr.g = clr.r = 1.0f;
  538. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  539. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  540. clr.b = clr.g = clr.r = 0.05f;
  541. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  542. if (0 != this->m_pcHeader->num_skins)
  543. {
  544. aiString szString;
  545. memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3);
  546. szString.length = 2;
  547. pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
  548. }
  549. // now iterate through all triangles
  550. unsigned int iCurrent = 0;
  551. for (unsigned int i = 0; i < (unsigned int) this->m_pcHeader->num_tris;++i)
  552. {
  553. pcMesh->mFaces[i].mIndices = new unsigned int[3];
  554. pcMesh->mFaces[i].mNumIndices = 3;
  555. for (unsigned int c = 0; c < 3;++c,++iCurrent)
  556. {
  557. pcMesh->mFaces[i].mIndices[c] = iCurrent;
  558. // read vertices
  559. unsigned int iIndex = pcTriangles->vertex[c];
  560. if (iIndex >= (unsigned int)this->m_pcHeader->num_verts)
  561. {
  562. iIndex = this->m_pcHeader->num_verts-1;
  563. DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list.");
  564. }
  565. aiVector3D& vec = pcMesh->mVertices[iCurrent];
  566. vec.x = (float)pcVertices[iIndex].v[0] * this->m_pcHeader->scale[0];
  567. vec.x += this->m_pcHeader->translate[0];
  568. // (flip z and y component)
  569. vec.z = (float)pcVertices[iIndex].v[1] * this->m_pcHeader->scale[1];
  570. vec.z += this->m_pcHeader->translate[1];
  571. vec.y = (float)pcVertices[iIndex].v[2] * this->m_pcHeader->scale[2];
  572. vec.y += this->m_pcHeader->translate[2];
  573. // flip the Z-axis
  574. //pcMesh->mVertices[iBase+c].z *= -1.0f;
  575. // read the normal vector from the precalculated normal table
  576. pcMesh->mNormals[iCurrent] = *((const aiVector3D*)(&g_avNormals[std::min(
  577. int(pcVertices[iIndex].normalIndex),
  578. int(sizeof(g_avNormals) / sizeof(g_avNormals[0]))-1)]));
  579. //pcMesh->mNormals[iBase+c].z *= -1.0f;
  580. std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z );
  581. // read texture coordinates
  582. float s = (float)pcTexCoords[iIndex].s;
  583. float t = (float)pcTexCoords[iIndex].t;
  584. // translate texture coordinates
  585. if (0 == pcTriangles->facesfront &&
  586. 0 != pcTexCoords[iIndex].onseam)
  587. {
  588. s += this->m_pcHeader->skinwidth * 0.5f;
  589. }
  590. // Scale s and t to range from 0.0 to 1.0
  591. pcMesh->mTextureCoords[0][iCurrent].x = (s + 0.5f) / this->m_pcHeader->skinwidth;
  592. pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-(t + 0.5f) / this->m_pcHeader->skinheight;
  593. }
  594. pcTriangles++;
  595. }
  596. return;
  597. }
  598. // ------------------------------------------------------------------------------------------------
  599. void MDLImporter::InternReadFile_GameStudio( )
  600. {
  601. ai_assert(NULL != pScene);
  602. if(0 == this->m_pcHeader->num_frames)
  603. {
  604. throw new ImportErrorException( "[3DGS MDL] No frames found");
  605. }
  606. // allocate enough storage to hold all vertices and triangles
  607. aiMesh* pcMesh = new aiMesh();
  608. // current cursor position in the file
  609. const unsigned char* szCurrent = (const unsigned char*)(this->m_pcHeader+1);
  610. // need to read all textures
  611. for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->num_skins;++i)
  612. {
  613. union{const MDL::Skin* pcSkin;const MDL::GroupSkin* pcGroupSkin;};
  614. pcSkin = (const MDL::Skin*)szCurrent;
  615. // create one output image
  616. unsigned int iSkip = 0;
  617. if (5 <= this->iGSFileVersion)
  618. {
  619. // MDL5 format could contain MIPmaps
  620. this->CreateTextureARGB8_GS5((unsigned char*)pcSkin + sizeof(uint32_t),
  621. pcSkin->group,&iSkip);
  622. }
  623. else
  624. {
  625. this->CreateTextureARGB8_GS4((unsigned char*)pcSkin + sizeof(uint32_t),
  626. pcSkin->group,&iSkip);
  627. }
  628. // need to skip one image
  629. szCurrent += iSkip + sizeof(uint32_t);
  630. }
  631. // get a pointer to the texture coordinates
  632. const MDL::TexCoord_MDL3* pcTexCoords = (const MDL::TexCoord_MDL3*)szCurrent;
  633. szCurrent += sizeof(MDL::TexCoord_MDL3) * this->m_pcHeader->synctype;
  634. // NOTE: for MDLn formats syntype corresponds to the number of UV coords
  635. // get a pointer to the triangles
  636. const MDL::Triangle_MDL3* pcTriangles = (const MDL::Triangle_MDL3*)szCurrent;
  637. szCurrent += sizeof(MDL::Triangle_MDL3) * this->m_pcHeader->num_tris;
  638. pcMesh->mNumVertices = this->m_pcHeader->num_tris * 3;
  639. pcMesh->mNumFaces = this->m_pcHeader->num_tris;
  640. pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  641. pcMesh->mNumUVComponents[0] = 2;
  642. // there won't be more than one mesh inside the file
  643. pScene->mNumMaterials = 1;
  644. pScene->mRootNode = new aiNode();
  645. pScene->mRootNode->mNumMeshes = 1;
  646. pScene->mRootNode->mMeshes = new unsigned int[1];
  647. pScene->mRootNode->mMeshes[0] = 0;
  648. pScene->mMaterials = new aiMaterial*[1];
  649. pScene->mMaterials[0] = new MaterialHelper();
  650. pScene->mNumMeshes = 1;
  651. pScene->mMeshes = new aiMesh*[1];
  652. pScene->mMeshes[0] = pcMesh;
  653. std::vector<aiVector3D> vPositions;
  654. std::vector<aiVector3D> vTexCoords;
  655. std::vector<aiVector3D> vNormals;
  656. vPositions.resize(pScene->mMeshes[0]->mNumFaces*3,aiVector3D());
  657. vTexCoords.resize(pScene->mMeshes[0]->mNumFaces*3,aiVector3D());
  658. vNormals.resize(pScene->mMeshes[0]->mNumFaces*3,aiVector3D());
  659. // setup the material properties
  660. const int iMode = (int)aiShadingMode_Gouraud;
  661. MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
  662. pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  663. aiColor3D clr;
  664. clr.b = clr.g = clr.r = 1.0f;
  665. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  666. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  667. clr.b = clr.g = clr.r = 0.05f;
  668. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  669. if (0 != this->m_pcHeader->num_skins)
  670. {
  671. aiString szString;
  672. memcpy(szString.data,AI_MAKE_EMBEDDED_TEXNAME(0),3);
  673. szString.length = 2;
  674. pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
  675. }
  676. // now get a pointer to the first frame in the file
  677. const MDL::Frame* pcFrames = (const MDL::Frame*)szCurrent;
  678. // byte packed vertices
  679. if (0 == pcFrames->type || 3 == this->iGSFileVersion)
  680. {
  681. const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)
  682. (szCurrent + sizeof(uint32_t));
  683. // get a pointer to the vertices
  684. const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name) +
  685. sizeof(pcFirstFrame->name));
  686. // now iterate through all triangles
  687. unsigned int iCurrent = 0;
  688. for (unsigned int i = 0; i < (unsigned int) this->m_pcHeader->num_tris;++i)
  689. {
  690. pcMesh->mFaces[i].mIndices = new unsigned int[3];
  691. pcMesh->mFaces[i].mNumIndices = 3;
  692. for (unsigned int c = 0; c < 3;++c,++iCurrent)
  693. {
  694. pcMesh->mFaces[i].mIndices[c] = iCurrent;
  695. // read vertices
  696. unsigned int iIndex = pcTriangles->index_xyz[c];
  697. if (iIndex >= (unsigned int)this->m_pcHeader->num_verts)
  698. {
  699. iIndex = this->m_pcHeader->num_verts-1;
  700. DefaultLogger::get()->warn("Index overflow in MDL3/4/5/6 vertex list");
  701. }
  702. aiVector3D& vec = vPositions[iCurrent];
  703. vec.x = (float)pcVertices[iIndex].v[0] * this->m_pcHeader->scale[0];
  704. vec.x += this->m_pcHeader->translate[0];
  705. // (flip z and y component)
  706. vec.z = (float)pcVertices[iIndex].v[1] * this->m_pcHeader->scale[1];
  707. vec.z += this->m_pcHeader->translate[1];
  708. vec.y = (float)pcVertices[iIndex].v[2] * this->m_pcHeader->scale[2];
  709. vec.y += this->m_pcHeader->translate[2];
  710. // read the normal vector from the precalculated normal table
  711. vNormals[iCurrent] = *((const aiVector3D*)(&g_avNormals[std::min(
  712. int(pcVertices[iIndex].normalIndex),
  713. int(sizeof(g_avNormals) / sizeof(g_avNormals[0]))-1)]));
  714. //vNormals[iBase+c].z *= -1.0f;
  715. std::swap ( vNormals[iCurrent].y,vNormals[iCurrent].z );
  716. // read texture coordinates
  717. iIndex = pcTriangles->index_uv[c];
  718. // validate UV indices
  719. if (iIndex >= (unsigned int)this->m_pcHeader->synctype)
  720. {
  721. iIndex = this->m_pcHeader->synctype-1;
  722. DefaultLogger::get()->warn("Index overflow in MDL3/4/5/6 UV coord list");
  723. }
  724. float s = (float)pcTexCoords[iIndex].u;
  725. float t = (float)pcTexCoords[iIndex].v;
  726. // Scale s and t to range from 0.0 to 1.0
  727. if (5 != this->iGSFileVersion &&
  728. this->m_pcHeader->skinwidth && this->m_pcHeader->skinheight)
  729. {
  730. s = (s + 0.5f) / this->m_pcHeader->skinwidth;
  731. t = 1.0f-(t + 0.5f) / this->m_pcHeader->skinheight;
  732. }
  733. vTexCoords[iCurrent].x = s;
  734. vTexCoords[iCurrent].y = t;
  735. }
  736. pcTriangles++;
  737. }
  738. }
  739. // short packed vertices
  740. else
  741. {
  742. // now get a pointer to the first frame in the file
  743. const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*)
  744. (szCurrent + sizeof(uint32_t));
  745. // get a pointer to the vertices
  746. const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) +
  747. sizeof(pcFirstFrame->name));
  748. // now iterate through all triangles
  749. unsigned int iCurrent = 0;
  750. for (unsigned int i = 0; i < (unsigned int) this->m_pcHeader->num_tris;++i)
  751. {
  752. pcMesh->mFaces[i].mIndices = new unsigned int[3];
  753. pcMesh->mFaces[i].mNumIndices = 3;
  754. for (unsigned int c = 0; c < 3;++c,++iCurrent)
  755. {
  756. pcMesh->mFaces[i].mIndices[c] = iCurrent;
  757. // read vertices
  758. unsigned int iIndex = pcTriangles->index_xyz[c];
  759. if (iIndex >= (unsigned int)this->m_pcHeader->num_verts)
  760. {
  761. iIndex = this->m_pcHeader->num_verts-1;
  762. DefaultLogger::get()->warn("Index overflow in MDL3/4/5/6 vertex list");
  763. }
  764. aiVector3D& vec = vPositions[iCurrent];
  765. vec.x = (float)pcVertices[iIndex].v[0] * this->m_pcHeader->scale[0];
  766. vec.x += this->m_pcHeader->translate[0];
  767. // (flip z and y component)
  768. vec.z = (float)pcVertices[iIndex].v[1] * this->m_pcHeader->scale[1];
  769. vec.z += this->m_pcHeader->translate[1];
  770. vec.y = (float)pcVertices[iIndex].v[2] * this->m_pcHeader->scale[2];
  771. vec.y += this->m_pcHeader->translate[2];
  772. // read the normal vector from the precalculated normal table
  773. vNormals[iCurrent] = *((const aiVector3D*)(&g_avNormals[std::min(
  774. int(pcVertices[iIndex].normalIndex),
  775. int(sizeof(g_avNormals) / sizeof(g_avNormals[0]))-1)]));
  776. std::swap ( vNormals[iCurrent].y,vNormals[iCurrent].z );
  777. // read texture coordinates
  778. iIndex = pcTriangles->index_uv[c];
  779. // validate UV indices
  780. if (iIndex >= (unsigned int) this->m_pcHeader->synctype)
  781. {
  782. iIndex = this->m_pcHeader->synctype-1;
  783. DefaultLogger::get()->warn("Index overflow in MDL3/4/5/6 UV coord list");
  784. }
  785. float s = (float)pcTexCoords[iIndex].u;
  786. float t = (float)pcTexCoords[iIndex].v;
  787. // Scale s and t to range from 0.0 to 1.0
  788. if (5 != this->iGSFileVersion &&
  789. this->m_pcHeader->skinwidth && this->m_pcHeader->skinheight)
  790. {
  791. s = (s + 0.5f) / this->m_pcHeader->skinwidth;
  792. t = 1.0f-(t + 0.5f) / this->m_pcHeader->skinheight;
  793. }
  794. vTexCoords[iCurrent].x = s;
  795. vTexCoords[iCurrent].y = t;
  796. }
  797. pcTriangles++;
  798. }
  799. }
  800. // For MDL5 we will need to build valid texture coordinates
  801. // basing upon the file loaded (only support one file as skin)
  802. if (5 == this->iGSFileVersion)
  803. {
  804. if (0 != this->m_pcHeader->num_skins && 0 != this->pScene->mNumTextures)
  805. {
  806. aiTexture* pcTex = this->pScene->mTextures[0];
  807. // if the file is loaded in DDS format: get the size of the
  808. // texture from the header of the DDS file
  809. // skip three DWORDs and read first height, then the width
  810. unsigned int iWidth, iHeight;
  811. if (0 == pcTex->mHeight)
  812. {
  813. uint32_t* piPtr = (uint32_t*)pcTex->pcData;
  814. piPtr += 3;
  815. iHeight = (unsigned int)*piPtr++;
  816. iWidth = (unsigned int)*piPtr;
  817. }
  818. else
  819. {
  820. iWidth = pcTex->mWidth;
  821. iHeight = pcTex->mHeight;
  822. }
  823. for (std::vector<aiVector3D>::iterator
  824. i = vTexCoords.begin();
  825. i != vTexCoords.end();++i)
  826. {
  827. (*i).x /= iWidth;
  828. (*i).y /= iHeight;
  829. (*i).y = 1.0f- (*i).y;
  830. }
  831. }
  832. }
  833. // allocate output storage
  834. pScene->mMeshes[0]->mNumVertices = vPositions.size();
  835. pScene->mMeshes[0]->mVertices = new aiVector3D[vPositions.size()];
  836. pScene->mMeshes[0]->mNormals = new aiVector3D[vPositions.size()];
  837. pScene->mMeshes[0]->mTextureCoords[0] = new aiVector3D[vPositions.size()];
  838. // memcpy() the data to the c-syle arrays
  839. memcpy(pScene->mMeshes[0]->mVertices, &vPositions[0],
  840. vPositions.size() * sizeof(aiVector3D));
  841. memcpy(pScene->mMeshes[0]->mNormals, &vNormals[0],
  842. vPositions.size() * sizeof(aiVector3D));
  843. memcpy(pScene->mMeshes[0]->mTextureCoords[0], &vTexCoords[0],
  844. vPositions.size() * sizeof(aiVector3D));
  845. return;
  846. }
  847. // ------------------------------------------------------------------------------------------------
  848. void MDLImporter::ParseSkinLump_GameStudioA7(
  849. const unsigned char* szCurrent,
  850. const unsigned char** szCurrentOut,
  851. std::vector<MaterialHelper*>& pcMats)
  852. {
  853. ai_assert(NULL != szCurrent);
  854. ai_assert(NULL != szCurrentOut);
  855. *szCurrentOut = szCurrent;
  856. const MDL::Skin_MDL7* pcSkin = (const MDL::Skin_MDL7*)szCurrent;
  857. szCurrent += 12;
  858. // allocate an output material
  859. MaterialHelper* pcMatOut = new MaterialHelper();
  860. pcMats.push_back(pcMatOut);
  861. aiTexture* pcNew = NULL;
  862. // get the type of the skin
  863. unsigned int iMasked = (unsigned int)(pcSkin->typ & 0xF);
  864. // skip length of file name
  865. szCurrent += AI_MDL7_MAX_TEXNAMESIZE;
  866. if (0x1 == iMasked)
  867. {
  868. // ***** REFERENCE TO ANOTHER SKIN INDEX *****
  869. // NOTE: Documentation - if you can call it a documentation, I prefer
  870. // the expression "rubbish" - states it is currently unused. However,
  871. // I don't know what ideas the terrible developers of Conitec will
  872. // have tomorrow, so Im going to implement it.
  873. int referrer = pcSkin->width;
  874. pcMatOut->AddProperty<int>(&referrer,1,"quakquakquak");
  875. }
  876. else if (0x6 == iMasked)
  877. {
  878. // ***** EMBEDDED DDS FILE *****
  879. if (1 != pcSkin->height)
  880. {
  881. DefaultLogger::get()->warn("Found a reference to an embedded DDS texture, "
  882. "but texture height is not equal to 1, which is not supported by MED");
  883. }
  884. pcNew = new aiTexture();
  885. pcNew->mHeight = 0;
  886. pcNew->achFormatHint[0] = 'd';
  887. pcNew->achFormatHint[1] = 'd';
  888. pcNew->achFormatHint[2] = 's';
  889. pcNew->achFormatHint[3] = '\0';
  890. pcNew->pcData = (aiTexel*) new unsigned char[pcNew->mWidth];
  891. memcpy(pcNew->pcData,szCurrent,pcNew->mWidth);
  892. szCurrent += pcSkin->width;
  893. }
  894. if (0x7 == iMasked)
  895. {
  896. // ***** REFERENCE TO EXTERNAL FILE FILE *****
  897. if (1 != pcSkin->height)
  898. {
  899. DefaultLogger::get()->warn("Found a reference to an external texture, "
  900. "but texture height is not equal to 1, which is not supported by MED");
  901. }
  902. aiString szFile;
  903. const size_t iLen = strlen((const char*)szCurrent);
  904. size_t iLen2 = iLen+1;
  905. iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
  906. memcpy(szFile.data,(const char*)szCurrent,iLen2);
  907. szFile.length = iLen;
  908. szCurrent += iLen2;
  909. // place this as diffuse texture
  910. pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
  911. }
  912. else if (0 != iMasked || 0 == pcSkin->typ)
  913. {
  914. // ***** STANDARD COLOR TEXTURE *****
  915. pcNew = new aiTexture();
  916. if (0 == pcSkin->height || 0 == pcSkin->width)
  917. {
  918. DefaultLogger::get()->warn("Found embedded texture, but its width "
  919. "an height are both 0. Is this a joke?");
  920. // generate an empty chess pattern
  921. pcNew->mWidth = pcNew->mHeight = 8;
  922. pcNew->pcData = new aiTexel[64];
  923. for (unsigned int x = 0; x < 8;++x)
  924. {
  925. for (unsigned int y = 0; y < 8;++y)
  926. {
  927. bool bSet = false;
  928. if (0 == x % 2 && 0 != y % 2 ||
  929. 0 != x % 2 && 0 == y % 2)bSet = true;
  930. aiTexel* pc = &pcNew->pcData[y * 8 + x];
  931. if (bSet)pc->r = pc->b = pc->g = 0xFF;
  932. else pc->r = pc->b = pc->g = 0;
  933. pc->a = 0xFF;
  934. }
  935. }
  936. }
  937. else
  938. {
  939. // it is a standard color texture. Fill in width and height
  940. // and call the same function we used for loading MDL5 files
  941. pcNew->mWidth = pcSkin->width;
  942. pcNew->mHeight = pcSkin->height;
  943. unsigned int iSkip = 0;
  944. this->ParseTextureColorData(szCurrent,iMasked,&iSkip,pcNew);
  945. // skip length of texture data
  946. szCurrent += iSkip;
  947. }
  948. }
  949. // check whether a material definition is contained in the skin
  950. if (pcSkin->typ & AI_MDL7_SKINTYPE_MATERIAL)
  951. {
  952. const MDL::Material_MDL7* pcMatIn = (const MDL::Material_MDL7*)szCurrent;
  953. szCurrent = (unsigned char*)(pcMatIn+1);
  954. aiColor4D clrTemp;
  955. // read diffuse color
  956. clrTemp.a = 1.0f; //pcMatIn->Diffuse.a;
  957. clrTemp.r = pcMatIn->Diffuse.r;
  958. clrTemp.g = pcMatIn->Diffuse.g;
  959. clrTemp.b = pcMatIn->Diffuse.b;
  960. pcMatOut->AddProperty<aiColor4D>(&clrTemp,1,AI_MATKEY_COLOR_DIFFUSE);
  961. // read specular color
  962. clrTemp.a = 1.0f; //pcMatIn->Specular.a;
  963. clrTemp.r = pcMatIn->Specular.r;
  964. clrTemp.g = pcMatIn->Specular.g;
  965. clrTemp.b = pcMatIn->Specular.b;
  966. pcMatOut->AddProperty<aiColor4D>(&clrTemp,1,AI_MATKEY_COLOR_SPECULAR);
  967. // read ambient color
  968. clrTemp.a = 1.0f; //pcMatIn->Ambient.a;
  969. clrTemp.r = pcMatIn->Ambient.r;
  970. clrTemp.g = pcMatIn->Ambient.g;
  971. clrTemp.b = pcMatIn->Ambient.b;
  972. pcMatOut->AddProperty<aiColor4D>(&clrTemp,1,AI_MATKEY_COLOR_AMBIENT);
  973. // read emissive color
  974. clrTemp.a = 1.0f; //pcMatIn->Emissive.a;
  975. clrTemp.r = pcMatIn->Emissive.r;
  976. clrTemp.g = pcMatIn->Emissive.g;
  977. clrTemp.b = pcMatIn->Emissive.b;
  978. pcMatOut->AddProperty<aiColor4D>(&clrTemp,1,AI_MATKEY_COLOR_EMISSIVE);
  979. // FIX: Take the opacity from the ambient color
  980. clrTemp.a = pcMatIn->Ambient.a;
  981. pcMatOut->AddProperty<float>(&clrTemp.a,1,AI_MATKEY_OPACITY);
  982. // read phong power
  983. int iShadingMode = (int)aiShadingMode_Gouraud;
  984. if (0.0f != pcMatIn->Power)
  985. {
  986. iShadingMode = (int)aiShadingMode_Phong;
  987. pcMatOut->AddProperty<float>(&pcMatIn->Power,1,AI_MATKEY_SHININESS);
  988. }
  989. pcMatOut->AddProperty<int>(&iShadingMode,1,AI_MATKEY_SHADING_MODEL);
  990. }
  991. // if an ASCII effect description (HLSL?) is contained in the file,
  992. // we can simply ignore it ...
  993. if (pcSkin->typ & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF)
  994. {
  995. int32_t iMe = *((int32_t*)szCurrent);
  996. szCurrent += sizeof(char) * iMe + sizeof(int32_t);
  997. }
  998. // if an embedded texture has been loaded setup the corresponding
  999. // data structures in the aiScene instance
  1000. if (NULL != pcNew)
  1001. {
  1002. // place this as diffuse texture
  1003. char szCurrent[5];
  1004. sprintf(szCurrent,"*%i",this->pScene->mNumTextures);
  1005. aiString szFile;
  1006. const size_t iLen = strlen((const char*)szCurrent);
  1007. size_t iLen2 = iLen+1;
  1008. iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
  1009. memcpy(szFile.data,(const char*)szCurrent,iLen2);
  1010. szFile.length = iLen;
  1011. pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
  1012. // store the texture
  1013. aiTexture** pc = this->pScene->mTextures;
  1014. this->pScene->mTextures = new aiTexture*[this->pScene->mNumTextures+1];
  1015. for (unsigned int i = 0; i < this->pScene->mNumTextures;++i)
  1016. this->pScene->mTextures[i] = pc[i];
  1017. this->pScene->mTextures[this->pScene->mNumTextures] = pcNew;
  1018. this->pScene->mNumTextures++;
  1019. delete[] pc;
  1020. }
  1021. // place the name of the skin in the material
  1022. const size_t iLen = strlen(pcSkin->texture_name);
  1023. if (0 != iLen)
  1024. {
  1025. aiString szFile;
  1026. memcpy(szFile.data,pcSkin->texture_name,sizeof(pcSkin->texture_name));
  1027. szFile.length = iLen;
  1028. pcMatOut->AddProperty(&szFile,AI_MATKEY_NAME);
  1029. }
  1030. *szCurrentOut = szCurrent;
  1031. return;
  1032. }
  1033. #define _AI_MDL7_ACCESS(_data, _index, _limit, _type) \
  1034. (*((const _type*)(((const char*)_data) + _index * _limit)))
  1035. #define _AI_MDL7_ACCESS_VERT(_data, _index, _limit) \
  1036. _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7)
  1037. // ------------------------------------------------------------------------------------------------
  1038. void MDLImporter::ValidateHeader_GameStudioA7(const MDL::Header_MDL7* pcHeader)
  1039. {
  1040. ai_assert(NULL != pcHeader);
  1041. if (sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size)
  1042. {
  1043. // LOG
  1044. throw new ImportErrorException(
  1045. "[3DGS MDL7] sizeof(MDL::ColorValue_MDL7) != pcHeader->colorvalue_stc_size");
  1046. }
  1047. if (sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size)
  1048. {
  1049. // LOG
  1050. throw new ImportErrorException(
  1051. "[3DGS MDL7] sizeof(MDL::TexCoord_MDL7) != pcHeader->skinpoint_stc_size");
  1052. }
  1053. if (sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size)
  1054. {
  1055. // LOG
  1056. throw new ImportErrorException(
  1057. "sizeof(MDL::Skin_MDL7) != pcHeader->skin_stc_size");
  1058. }
  1059. // if there are no groups ... how should we load such a file?
  1060. if(0 == pcHeader->groups_num)
  1061. {
  1062. // LOG
  1063. throw new ImportErrorException( "[3DGS MDL7] No frames found");
  1064. }
  1065. return;
  1066. }
  1067. // ------------------------------------------------------------------------------------------------
  1068. void MDLImporter::InternReadFile_GameStudioA7( )
  1069. {
  1070. ai_assert(NULL != pScene);
  1071. // current cursor position in the file
  1072. const MDL::Header_MDL7* pcHeader = (const MDL::Header_MDL7*)this->m_pcHeader;
  1073. const unsigned char* szCurrent = (const unsigned char*)(pcHeader+1);
  1074. // validate the header of the file. There are some structure
  1075. // sizes that are expected by the loader to be constant
  1076. this->ValidateHeader_GameStudioA7(pcHeader);
  1077. // skip all bones
  1078. szCurrent += sizeof(MDL::Bone_MDL7) * pcHeader->bones_num;
  1079. // allocate a material list
  1080. std::vector<MaterialHelper*> pcMats;
  1081. // vector to hold all created meshes
  1082. std::vector<aiMesh*> avOutList;
  1083. avOutList.reserve(pcHeader->groups_num);
  1084. // read all groups
  1085. for (unsigned int iGroup = 0; iGroup < (unsigned int)pcHeader->groups_num;++iGroup)
  1086. {
  1087. const MDL::Group_MDL7* pcGroup = (const MDL::Group_MDL7*)szCurrent;
  1088. szCurrent = (const unsigned char*)(pcGroup+1);
  1089. if (1 != pcGroup->typ)
  1090. {
  1091. // Not a triangle-based mesh
  1092. DefaultLogger::get()->warn("[3DGS MDL7] Mesh group is not basing on"
  1093. "triangles. Continuing happily");
  1094. }
  1095. // read all skins
  1096. pcMats.reserve(pcMats.size() + pcGroup->numskins);
  1097. for (unsigned int iSkin = 0; iSkin < (unsigned int)pcGroup->numskins;++iSkin)
  1098. {
  1099. this->ParseSkinLump_GameStudioA7(szCurrent,&szCurrent,pcMats);
  1100. }
  1101. // if we have absolutely no skin loaded we need to generate a default material
  1102. if (pcMats.empty())
  1103. {
  1104. const int iMode = (int)aiShadingMode_Gouraud;
  1105. pcMats.push_back(new MaterialHelper());
  1106. MaterialHelper* pcHelper = (MaterialHelper*)pcMats[0];
  1107. pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  1108. aiColor3D clr;
  1109. clr.b = clr.g = clr.r = 0.6f;
  1110. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  1111. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  1112. clr.b = clr.g = clr.r = 0.05f;
  1113. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  1114. }
  1115. // now get a pointer to all texture coords in the group
  1116. const MDL::TexCoord_MDL7* pcGroupUVs = (const MDL::TexCoord_MDL7*)szCurrent;
  1117. szCurrent += pcHeader->skinpoint_stc_size * pcGroup->num_stpts;
  1118. // now get a pointer to all triangle in the group
  1119. const MDL::Triangle_MDL7* pcGroupTris = (const MDL::Triangle_MDL7*)szCurrent;
  1120. szCurrent += pcHeader->triangle_stc_size * pcGroup->numtris;
  1121. // now get a pointer to all vertices in the group
  1122. const MDL::Vertex_MDL7* pcGroupVerts = (const MDL::Vertex_MDL7*)szCurrent;
  1123. szCurrent += pcHeader->mainvertex_stc_size * pcGroup->numverts;
  1124. // build output vectors
  1125. std::vector<aiVector3D> vPositions;
  1126. vPositions.resize(pcGroup->numtris * 3);
  1127. std::vector<aiVector3D> vNormals;
  1128. vNormals.resize(pcGroup->numtris * 3);
  1129. std::vector<aiVector3D> vTextureCoords1;
  1130. vTextureCoords1.resize(pcGroup->numtris * 3,
  1131. aiVector3D(std::numeric_limits<float>::quiet_NaN(),0.0f,0.0f));
  1132. std::vector<aiVector3D> vTextureCoords2;
  1133. bool bNeed2UV = false;
  1134. if (pcHeader->triangle_stc_size >= sizeof(MDL::Triangle_MDL7))
  1135. {
  1136. vTextureCoords2.resize(pcGroup->numtris * 3,
  1137. aiVector3D(std::numeric_limits<float>::quiet_NaN(),0.0f,0.0f));
  1138. bNeed2UV = true;
  1139. }
  1140. MDL::IntFace_MDL7* pcFaces = new MDL::IntFace_MDL7[pcGroup->numtris];
  1141. // iterate through all triangles and build valid display lists
  1142. for (unsigned int iTriangle = 0; iTriangle < (unsigned int)pcGroup->numtris; ++iTriangle)
  1143. {
  1144. // iterate through all indices of the current triangle
  1145. for (unsigned int c = 0; c < 3;++c)
  1146. {
  1147. // validate the vertex index
  1148. unsigned int iIndex = pcGroupTris->v_index[c];
  1149. if(iIndex > (unsigned int)pcGroup->numverts)
  1150. {
  1151. // LOG
  1152. iIndex = pcGroup->numverts-1;
  1153. DefaultLogger::get()->warn("Index overflow in MDL7 vertex list");
  1154. }
  1155. unsigned int iOutIndex = iTriangle * 3 + c;
  1156. // write the output face index
  1157. pcFaces[iTriangle].mIndices[c] = iOutIndex;
  1158. // swap z and y axis
  1159. vPositions[iOutIndex].x = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .x;
  1160. vPositions[iOutIndex].z = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y;
  1161. vPositions[iOutIndex].y = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z;
  1162. // now read the normal vector
  1163. if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size)
  1164. {
  1165. // read the full normal vector
  1166. vNormals[iOutIndex].x = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0];
  1167. vNormals[iOutIndex].z = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1];
  1168. vNormals[iOutIndex].y = _AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2];
  1169. // FIX: It seems to be necessary to invert all normals
  1170. vNormals[iOutIndex].x *= -1.0f;
  1171. vNormals[iOutIndex].y *= -1.0f;
  1172. vNormals[iOutIndex].z *= -1.0f;
  1173. }
  1174. else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)
  1175. {
  1176. // read the normal vector from Quake2's smart table
  1177. vNormals[iOutIndex] = *((const aiVector3D*)(&g_avNormals[std::min(
  1178. int(_AI_MDL7_ACCESS_VERT(pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm162index),
  1179. int(sizeof(g_avNormals) / sizeof(g_avNormals[0]))-1)]));
  1180. std::swap(vNormals[iOutIndex].z,vNormals[iOutIndex].y);
  1181. }
  1182. // validate and process the first uv coordinate set
  1183. // *************************************************************
  1184. const unsigned int iMin = sizeof(MDL::Triangle_MDL7)-
  1185. sizeof(MDL::SkinSet_MDL7)-sizeof(uint32_t);
  1186. const unsigned int iMin2 = sizeof(MDL::Triangle_MDL7)-
  1187. sizeof(MDL::SkinSet_MDL7);
  1188. if (pcHeader->triangle_stc_size >= iMin)
  1189. {
  1190. iIndex = pcGroupTris->skinsets[0].st_index[c];
  1191. if(iIndex > (unsigned int)pcGroup->num_stpts)
  1192. {
  1193. iIndex = pcGroup->num_stpts-1;
  1194. }
  1195. float u = pcGroupUVs[iIndex].u;
  1196. float v = 1.0f-pcGroupUVs[iIndex].v;
  1197. vTextureCoords1[iOutIndex].x = u;
  1198. vTextureCoords1[iOutIndex].y = v;
  1199. // assign the material index, but only if it is existing
  1200. if (pcHeader->triangle_stc_size >= iMin2)
  1201. {
  1202. pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material;
  1203. }
  1204. }
  1205. // validate and process the second uv coordinate set
  1206. // *************************************************************
  1207. if (pcHeader->triangle_stc_size >= sizeof(MDL::Triangle_MDL7))
  1208. {
  1209. iIndex = pcGroupTris->skinsets[1].st_index[c];
  1210. if(iIndex > (unsigned int)pcGroup->num_stpts)
  1211. {
  1212. iIndex = pcGroup->num_stpts-1;
  1213. }
  1214. float u = pcGroupUVs[iIndex].u;
  1215. float v = 1.0f-pcGroupUVs[iIndex].v;
  1216. vTextureCoords2[iOutIndex].x = u;
  1217. vTextureCoords2[iOutIndex].y = v;
  1218. // check whether we do really need the second texture
  1219. // coordinate set ... wastes memory and loading time
  1220. if (0 != iIndex && (u != vTextureCoords1[iOutIndex].x ||
  1221. v != vTextureCoords1[iOutIndex].y))
  1222. {
  1223. bNeed2UV = true;
  1224. }
  1225. // if the material differs, we need a second skin, too
  1226. if (pcGroupTris->skinsets[1].material != pcGroupTris->skinsets[0].material)
  1227. {
  1228. bNeed2UV = true;
  1229. }
  1230. // assign the material index
  1231. pcFaces[iTriangle].iMatIndex[1] = pcGroupTris->skinsets[1].material;
  1232. }
  1233. }
  1234. // get the next triangle in the list
  1235. pcGroupTris = (const MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcHeader->triangle_stc_size);
  1236. }
  1237. // if we don't need a second set of texture coordinates there is no reason to keep it in memory ...
  1238. std::vector<unsigned int>** aiSplit;
  1239. unsigned int iNumMaterials = 0;
  1240. if (!bNeed2UV)
  1241. {
  1242. vTextureCoords2.clear();
  1243. // allocate the array
  1244. aiSplit = new std::vector<unsigned int>*[pcMats.size()];
  1245. iNumMaterials = pcMats.size();
  1246. for (unsigned int m = 0; m < pcMats.size();++m)
  1247. aiSplit[m] = new std::vector<unsigned int>();
  1248. // iterate through all faces and sort by material
  1249. for (unsigned int iFace = 0; iFace < (unsigned int)pcGroup->numtris;++iFace)
  1250. {
  1251. // check range
  1252. if (pcFaces[iFace].iMatIndex[0] >= iNumMaterials)
  1253. {
  1254. // use the last material instead
  1255. aiSplit[iNumMaterials-1]->push_back(iFace);
  1256. // sometimes MED writes -1, but normally only if there is only
  1257. // one skin assigned. No warning in this case
  1258. if(0xFFFFFFFF != pcFaces[iFace].iMatIndex[0])
  1259. DefaultLogger::get()->warn("Index overflow in MDL7 material list [#0]");
  1260. }
  1261. else aiSplit[pcFaces[iFace].iMatIndex[0]]->push_back(iFace);
  1262. }
  1263. }
  1264. else
  1265. {
  1266. // we need to build combined materials for each combination of
  1267. std::vector<MDL::IntMaterial_MDL7> avMats;
  1268. avMats.reserve(pcMats.size()*2);
  1269. std::vector<std::vector<unsigned int>* > aiTempSplit;
  1270. aiTempSplit.reserve(pcMats.size()*2);
  1271. for (unsigned int m = 0; m < pcMats.size();++m)
  1272. aiTempSplit[m] = new std::vector<unsigned int>();
  1273. // iterate through all faces and sort by material
  1274. for (unsigned int iFace = 0; iFace < (unsigned int)pcGroup->numtris;++iFace)
  1275. {
  1276. // check range
  1277. unsigned int iMatIndex = pcFaces[iFace].iMatIndex[0];
  1278. if (iMatIndex >= iNumMaterials)
  1279. {
  1280. iMatIndex = iNumMaterials-1;
  1281. // sometimes MED writes -1, but normally only if there is only
  1282. // one skin assigned. No warning in this case
  1283. if(0xFFFFFFFF != iMatIndex)
  1284. DefaultLogger::get()->warn("Index overflow in MDL7 material list [#1]");
  1285. }
  1286. unsigned int iMatIndex2 = pcFaces[iFace].iMatIndex[1];
  1287. if (iMatIndex2 >= iNumMaterials)
  1288. {
  1289. // sometimes MED writes -1, but normally only if there is only
  1290. // one skin assigned. No warning in this case
  1291. if(0xFFFFFFFF != iMatIndex2)
  1292. DefaultLogger::get()->warn("Index overflow in MDL7 material list [#2]");
  1293. }
  1294. // do a slow O(log(n)*n) seach in the list ...
  1295. unsigned int iNum = 0;
  1296. bool bFound = false;
  1297. for (std::vector<MDL::IntMaterial_MDL7>::iterator
  1298. i = avMats.begin();
  1299. i != avMats.end();++i,++iNum)
  1300. {
  1301. if ((*i).iOldMatIndices[0] == iMatIndex &&
  1302. (*i).iOldMatIndices[1] == iMatIndex2)
  1303. {
  1304. // reuse this material
  1305. bFound = true;
  1306. break;
  1307. }
  1308. }
  1309. if (!bFound)
  1310. {
  1311. // build a new material ...
  1312. MDL::IntMaterial_MDL7 sHelper;
  1313. sHelper.pcMat = new MaterialHelper();
  1314. sHelper.iOldMatIndices[0] = iMatIndex;
  1315. sHelper.iOldMatIndices[1] = iMatIndex2;
  1316. this->JoinSkins_GameStudioA7(pcMats[iMatIndex],pcMats[iMatIndex2],sHelper.pcMat);
  1317. // and add it to the list
  1318. avMats.push_back(sHelper);
  1319. iNum = avMats.size()-1;
  1320. }
  1321. // adjust the size of the file array
  1322. if (iNum == aiTempSplit.size())
  1323. {
  1324. aiTempSplit.push_back(new std::vector<unsigned int>());
  1325. }
  1326. aiTempSplit[iNum]->push_back(iFace);
  1327. }
  1328. // now add the newly created materials to the old list
  1329. if (0 == iGroup)
  1330. {
  1331. pcMats.resize(avMats.size());
  1332. for (unsigned int o = 0; o < avMats.size();++o)
  1333. pcMats[o] = avMats[o].pcMat;
  1334. }
  1335. else
  1336. {
  1337. // TODO: This might result in redundant materials ...
  1338. unsigned int iOld = pcMats.size();
  1339. pcMats.resize(pcMats.size() + avMats.size());
  1340. for (unsigned int o = iOld; o < avMats.size();++o)
  1341. pcMats[o] = avMats[o].pcMat;
  1342. }
  1343. iNumMaterials = pcMats.size();
  1344. // and build the final face-to-material array
  1345. aiSplit = new std::vector<unsigned int>*[aiTempSplit.size()];
  1346. for (unsigned int m = 0; m < iNumMaterials;++m)
  1347. aiSplit[m] = aiTempSplit[m];
  1348. // no need to delete the member of aiTempSplit
  1349. }
  1350. // now generate output meshes
  1351. unsigned int iOldSize = avOutList.size();
  1352. this->GenerateOutputMeshes_GameStudioA7(
  1353. (const std::vector<unsigned int>**)aiSplit,pcMats,
  1354. avOutList,pcFaces,vPositions,vNormals, vTextureCoords1,vTextureCoords2);
  1355. // store the group index temporarily
  1356. ai_assert(AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3);
  1357. for (unsigned int l = iOldSize;l < avOutList.size();++l)
  1358. {
  1359. avOutList[l]->mNumUVComponents[2] = iGroup;
  1360. }
  1361. // delete the face-to-material helper array
  1362. for (unsigned int m = 0; m < iNumMaterials;++m)
  1363. delete aiSplit[m];
  1364. delete[] aiSplit;
  1365. // now we need to skip all faces
  1366. for(unsigned int iFrame = 0; iFrame < (unsigned int)pcGroup->numframes;++iFrame)
  1367. {
  1368. const MDL::Frame_MDL7* pcFrame = (const MDL::Frame_MDL7*)szCurrent;
  1369. unsigned int iAdd = pcHeader->frame_stc_size +
  1370. pcFrame->vertices_count * pcHeader->framevertex_stc_size +
  1371. pcFrame->transmatrix_count * pcHeader->bonetrans_stc_size;
  1372. if (((unsigned int)szCurrent - (unsigned int)pcHeader) + iAdd > (unsigned int)pcHeader->data_size)
  1373. {
  1374. DefaultLogger::get()->warn("Index overflow in frame area. Ignoring frames");
  1375. // don't parse more groups if we can't even read one
  1376. goto __BREAK_OUT;
  1377. }
  1378. szCurrent += iAdd;
  1379. }
  1380. }
  1381. __BREAK_OUT: // EVIL ;-)
  1382. // now we need to build a final mesh list
  1383. this->pScene->mNumMeshes = avOutList.size();
  1384. this->pScene->mMeshes = new aiMesh*[avOutList.size()];
  1385. for (unsigned int i = 0; i < avOutList.size();++i)
  1386. {
  1387. this->pScene->mMeshes[i] = avOutList[i];
  1388. }
  1389. // build a final material list. Offset all mesh material indices
  1390. this->pScene->mNumMaterials = pcMats.size();
  1391. this->pScene->mMaterials = new aiMaterial*[this->pScene->mNumMaterials];
  1392. for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i)
  1393. this->pScene->mMaterials[i] = pcMats[i];
  1394. // search for referrer materials
  1395. for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i)
  1396. {
  1397. int iIndex = 0;
  1398. if (AI_SUCCESS == aiGetMaterialInteger(this->pScene->mMaterials[i],
  1399. "quakquakquak", &iIndex) )
  1400. {
  1401. for (unsigned int a = 0; a < avOutList.size();++a)
  1402. {
  1403. if (i == avOutList[a]->mMaterialIndex)
  1404. {
  1405. avOutList[a]->mMaterialIndex = iIndex;
  1406. }
  1407. }
  1408. // TODO: Remove the material from the list
  1409. }
  1410. }
  1411. // now generate a nodegraph whose rootnode references all meshes
  1412. this->pScene->mRootNode = new aiNode();
  1413. this->pScene->mRootNode->mNumMeshes = this->pScene->mNumMeshes;
  1414. this->pScene->mRootNode->mMeshes = new unsigned int[this->pScene->mRootNode->mNumMeshes];
  1415. for (unsigned int i = 0; i < this->pScene->mRootNode->mNumMeshes;++i)
  1416. this->pScene->mRootNode->mMeshes[i] = i;
  1417. // seems we're finished now
  1418. return;
  1419. }
  1420. // ------------------------------------------------------------------------------------------------
  1421. void MDLImporter::GenerateOutputMeshes_GameStudioA7(
  1422. const std::vector<unsigned int>** aiSplit,
  1423. const std::vector<MaterialHelper*>& pcMats,
  1424. std::vector<aiMesh*>& avOutList,
  1425. const MDL::IntFace_MDL7* pcFaces,
  1426. const std::vector<aiVector3D>& vPositions,
  1427. const std::vector<aiVector3D>& vNormals,
  1428. const std::vector<aiVector3D>& vTextureCoords1,
  1429. const std::vector<aiVector3D>& vTextureCoords2)
  1430. {
  1431. for (unsigned int i = 0; i < pcMats.size();++i)
  1432. {
  1433. if (!aiSplit[i]->empty())
  1434. {
  1435. // allocate the output mesh
  1436. aiMesh* pcMesh = new aiMesh();
  1437. pcMesh->mNumUVComponents[0] = 2;
  1438. pcMesh->mMaterialIndex = i;
  1439. // allocate output storage
  1440. pcMesh->mNumFaces = aiSplit[i]->size();
  1441. pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  1442. pcMesh->mNumVertices = pcMesh->mNumFaces*3;
  1443. pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  1444. pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  1445. pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  1446. if (!vTextureCoords2.empty())
  1447. {
  1448. pcMesh->mNumUVComponents[1] = 2;
  1449. pcMesh->mTextureCoords[1] = new aiVector3D[pcMesh->mNumVertices];
  1450. }
  1451. // iterate through all faces and build an unique set of vertices
  1452. unsigned int iCurrent = 0;
  1453. for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace)
  1454. {
  1455. pcMesh->mFaces[iFace].mNumIndices = 3;
  1456. pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
  1457. unsigned int iSrcFace = aiSplit[i]->operator[](iFace);
  1458. const MDL::IntFace_MDL7& oldFace = pcFaces[iSrcFace];
  1459. // iterate through all face indices
  1460. for (unsigned int c = 0; c < 3;++c)
  1461. {
  1462. pcMesh->mVertices[iCurrent] = vPositions[oldFace.mIndices[c]];
  1463. pcMesh->mNormals[iCurrent] = vNormals[oldFace.mIndices[c]];
  1464. pcMesh->mTextureCoords[0][iCurrent] = vTextureCoords1[oldFace.mIndices[c]];
  1465. if (!vTextureCoords2.empty())
  1466. {
  1467. pcMesh->mTextureCoords[1][iCurrent] = vTextureCoords2[oldFace.mIndices[c]];
  1468. }
  1469. pcMesh->mFaces[iFace].mIndices[c] = iCurrent;
  1470. ++iCurrent;
  1471. }
  1472. }
  1473. // add the mesh to the list of output meshes
  1474. avOutList.push_back(pcMesh);
  1475. }
  1476. }
  1477. return;
  1478. }
  1479. // ------------------------------------------------------------------------------------------------
  1480. void MDLImporter::JoinSkins_GameStudioA7(
  1481. MaterialHelper* pcMat1,
  1482. MaterialHelper* pcMat2,
  1483. MaterialHelper* pcMatOut)
  1484. {
  1485. ai_assert(NULL != pcMat1);
  1486. ai_assert(NULL != pcMat2);
  1487. ai_assert(NULL != pcMatOut);
  1488. // first create a full copy of the first skin property set
  1489. // and assign it to the output material
  1490. MaterialHelper::CopyPropertyList(pcMatOut,pcMat1);
  1491. int iVal = 0;
  1492. pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
  1493. // then extract the diffuse texture from the second skin,
  1494. // setup 1 as UV source and we have it
  1495. aiString sString;
  1496. if(AI_SUCCESS == aiGetMaterialString ( pcMat2, AI_MATKEY_TEXTURE_DIFFUSE(0),&sString ))
  1497. {
  1498. iVal = 1;
  1499. pcMatOut->AddProperty<int>(&iVal,1,AI_MATKEY_UVWSRC_DIFFUSE(1));
  1500. pcMatOut->AddProperty(&sString,AI_MATKEY_TEXTURE_DIFFUSE(1));
  1501. }
  1502. return;
  1503. }