MDLLoader.cpp 61 KB

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