PageRenderTime 95ms CodeModel.GetById 52ms RepoModel.GetById 2ms app.codeStats 0ms

/src/shared/ADTFile.cpp

https://github.com/shlainn/pseuwow
C++ | 384 lines | 309 code | 24 blank | 51 comment | 76 complexity | b76dabe73a535d0edf66e6fb42eb9f5a MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0
  1. #include <fstream>
  2. #include "common.h"
  3. #include "ADTFile.h"
  4. inline void flipcc(uint8 *fcc)
  5. {
  6. char t;
  7. t=fcc[0];
  8. fcc[0]=fcc[3];
  9. fcc[3]=t;
  10. t=fcc[1];
  11. fcc[1]=fcc[2];
  12. fcc[2]=t;
  13. }
  14. void MCAL_decompress(uint8 *inbuf, uint8 *outbuf)
  15. {
  16. /*
  17. How the decompression works
  18. * read a byte
  19. * check for sign bit
  20. * if set we are in fill mode else we are in copy mode
  21. * take the 7 lesser bits of the first byte as a count indicator
  22. o fill mode: read the next byte an fill it by count in resulting alpha map
  23. o copy mode: read the next count bytes and copy them in the resulting alpha map
  24. * if the alpha map is complete we are done otherwise start at 1. again
  25. */
  26. // 21-10-2008 by Flow
  27. uint32 offI = 0; //offset IN buffer
  28. uint32 offO = 0; //offset OUT buffer
  29. while( offO < 4096 )
  30. {
  31. // fill or copy mode
  32. bool fill = inbuf[offI] & 0x80;
  33. unsigned n = inbuf[offI] & 0x7F;
  34. offI++;
  35. for( unsigned k = 0; k < n; k++ )
  36. {
  37. outbuf[offO] = inbuf[offI];
  38. offO++;
  39. if( !fill )
  40. offI++;
  41. }
  42. if( fill ) offI++;
  43. }
  44. }
  45. bool ADTFile::Load(std::string fn)
  46. {
  47. try
  48. {
  49. uint32 fs = GetFileSize(fn.c_str());
  50. if(!fs)
  51. return false;
  52. std::fstream fh;
  53. fh.open(fn.c_str(), std::ios_base::in | std::ios_base::binary);
  54. if(!fh.is_open())
  55. return false;
  56. ByteBuffer buf(fs);
  57. buf.resize(fs);
  58. fh.read((char*)buf.contents(),fs);
  59. fh.close();
  60. buf.rpos(0);
  61. return LoadMem(buf);
  62. }
  63. catch (...)
  64. {
  65. printf("ADTFile::Load() Exception\n");
  66. return false;
  67. }
  68. }
  69. bool ADTFile::LoadMem(ByteBuffer& buf)
  70. {
  71. uint32 texturecnt=0,modelcnt=0,wmocnt=0;
  72. uint32 size; // used for every chunk
  73. uint32 mcnkid=0;
  74. uint8 _cc[5];
  75. uint8 *fourcc = &_cc[0];
  76. fourcc[4]=0;
  77. while(buf.rpos() < buf.size())
  78. {
  79. buf.read(fourcc,4); flipcc(fourcc);
  80. buf.read((uint8*)&size,4);
  81. DEBUG(printf("ADT: reading '%s' size %u\n",fourcc,size));
  82. if(!strcmp((char*)fourcc,"MVER"))
  83. {
  84. buf >> _version;
  85. }
  86. else if(!strcmp((char*)fourcc,"MHDR"))
  87. {
  88. mhdr = buf.read<MHDR_chunk>();
  89. }
  90. else if(!strcmp((char*)fourcc,"MCIN"))
  91. {
  92. for(uint32 i = 0; i < CHUNKS_PER_TILE; i++)
  93. {
  94. mcin[i] = buf.read<MCIN_chunk>();
  95. //DEBUG(printf("ADT chunk %u at offset %u, size %u flags %X async %u\n",i,mcin[i].offset,mcin[i].size,mcin[i].flags,mcin[i].async));
  96. if(!mcin[i].offset)
  97. {
  98. printf("ADT: ERROR: chunk offset is NULL! Not loading.\n");
  99. return false;
  100. }
  101. }
  102. }
  103. else if(!strcmp((char*)fourcc,"MTEX"))
  104. {
  105. for(uint32 i=0;;i++)
  106. {
  107. std::string tex;
  108. memcpy(fourcc,buf.contents()+buf.rpos(),4);
  109. flipcc(fourcc);
  110. if(!memcmp(fourcc,"MMDX",4))
  111. break;
  112. buf >> tex;
  113. //DEBUG(printf("MTEX offset %u \"%s\"\n",buf.rpos(),tex.c_str()));
  114. _textures.push_back(tex);
  115. texturecnt++;
  116. }
  117. //DEBUG(printf("ADT: loaded %u textures\n",texturecnt));
  118. }
  119. else if(!strcmp((char*)fourcc,"MMDX"))
  120. {
  121. for(uint32 i=0;;i++)
  122. {
  123. std::string model;
  124. memcpy(fourcc,buf.contents()+buf.rpos(),4);
  125. flipcc(fourcc);
  126. if(!memcmp(fourcc,"MMID",4))
  127. break;
  128. buf >> model;
  129. //DEBUG(printf("MMDX offset %u \"%s\"\n",buf.rpos(),model.c_str()));
  130. _models.push_back(model);
  131. modelcnt++;
  132. }
  133. //DEBUG(printf("ADT: loaded %u models\n",modelcnt));
  134. }
  135. /*else if(!strcmp((char*)fourcc,"MMID"))
  136. {
  137. for(uint32 i = 0; i <= modelcnt; i++)
  138. {
  139. uint32 offs;
  140. buf >> offs; // we dont really need those offsets
  141. }
  142. }*/
  143. else if(!strcmp((char*)fourcc,"MWMO"))
  144. {
  145. for(uint32 i=0;;i++)
  146. {
  147. std::string wmo;
  148. memcpy(fourcc,buf.contents()+buf.rpos(),4);
  149. flipcc(fourcc);
  150. if(!memcmp(fourcc,"MWID",4))
  151. break;
  152. buf >> wmo;
  153. //DEBUG(printf("MWMO offset %u \"%s\"\n",buf.rpos(),wmo.c_str()));
  154. _wmos.push_back(wmo);
  155. wmocnt++;
  156. }
  157. }
  158. /*else if(!strcmp((char*)fourcc,"MWID"))
  159. {
  160. for(uint32 i = 0; i <= wmocnt; i++)
  161. {
  162. uint32 offs;
  163. buf >> offs; // we dont really need those offsets
  164. }
  165. }*/
  166. else if(!strcmp((char*)fourcc,"MDDF"))
  167. {
  168. uint32 ndoodads = size / sizeof(MDDF_chunk);
  169. //DEBUG(printf("ADT: Loading %u doodads.\n",ndoodads));
  170. for(uint32 i = 0; i<ndoodads; i++)
  171. {
  172. _doodadsp.push_back(buf.read<MDDF_chunk>());
  173. }
  174. }
  175. else if(!strcmp((char*)fourcc,"MODF"))
  176. {
  177. uint32 nwmos = size / 64;
  178. //DEBUG(printf("ADT: Loading %u wmos.\n",nwmos));
  179. for(uint32 i = 0; i<nwmos; i++)
  180. {
  181. _wmosp.push_back(buf.read<MODF_chunk>());
  182. }
  183. }
  184. else if(!strcmp((char*)fourcc,"MH2O"))
  185. {
  186. // TODO: Implement rest of this asap water levels needed for rendering/swimming!
  187. for(uint32 i = 0; i < CHUNKS_PER_TILE; i++)
  188. {
  189. uint32 ofsData1, used, ofsData2;
  190. buf >> ofsData1 >> used >> ofsData2;
  191. _chunks[i].haswater = used;
  192. if (used)
  193. {
  194. // ... http://madx.dk/wowdev/wiki/index.php?title=ADT#MH2O_chunk
  195. }
  196. }
  197. // remove me:
  198. buf.rpos(buf.rpos()+size-(4+4+4)*CHUNKS_PER_TILE);
  199. }
  200. else if(!strcmp((char*)fourcc,"MCNK"))
  201. {
  202. uint32 endpos = buf.rpos()+size;
  203. _chunks[mcnkid].hdr = buf.read<ADTMapChunkHeader>();
  204. uint8 _cc2[5];
  205. uint8 *mfcc = &_cc2[0];
  206. mfcc[4]=0;
  207. uint32 msize;
  208. bool mcal_compressed = false;
  209. while(buf.rpos()<endpos)
  210. {
  211. buf.read(mfcc,4); flipcc(mfcc);
  212. buf.read((uint8*)&msize,4);
  213. DEBUG(printf("ADT:MCNK[%u]: reading '%s' size %u\n",mcnkid,mfcc,msize));
  214. // HACKS to make it work properly
  215. if(!msize && !strcmp((char*)mfcc,"MCAL"))
  216. continue;
  217. if((!msize) && !strcmp((char*)mfcc,"MCLQ")) // size for MCLQ block is always 0
  218. msize = _chunks[mcnkid].hdr.sizeLiquid - 8; // but even the size in the header is somewhat wrong.. pfff
  219. //DEBUG(printf("ADT: MCNK: reading '%s' size %u\n",mfcc,msize));
  220. if(!strcmp((char*)mfcc,"MCVT"))
  221. {
  222. for(uint32 i = 0; i < 145; i++)
  223. {
  224. buf >>_chunks[mcnkid].vertices[i];
  225. }
  226. }
  227. else if(!strcmp((char*)mfcc,"MCNR"))
  228. {
  229. for(uint32 i = 0; i < 145; i++)
  230. {
  231. _chunks[mcnkid].normalvecs[i] = buf.read<NormalVector>();
  232. }
  233. // HACK: skip unk junk bytes
  234. if(msize==0x1B3)
  235. buf.rpos(buf.rpos()+0xD);
  236. }
  237. else if(!strcmp((char*)mfcc,"MCLY"))
  238. {
  239. _chunks[mcnkid].nTextures = msize / 16;
  240. ASSERT(msize/16 == _chunks[mcnkid].hdr.nLayers);
  241. for(uint32 i = 0; i < _chunks[mcnkid].nTextures; i++)
  242. {
  243. _chunks[mcnkid].layer[i] = buf.read<MCLY_chunk>();
  244. }
  245. if(_chunks[mcnkid].layer[_chunks[mcnkid].nTextures].flags & 0x200)
  246. mcal_compressed = true;
  247. }
  248. else if(!strcmp((char*)mfcc,"MCSH"))
  249. {
  250. buf.read((uint8*)&(_chunks[mcnkid].shadowmap),512);
  251. }
  252. else if(!strcmp((char*)mfcc,"MCAL"))
  253. {
  254. // we can NOT use _chunks[mcnkid].hdr.nLayers here... so we use: (full block size - header size) / single block size
  255. for(uint32 i = 0; i < (_chunks[mcnkid].hdr.sizeAlpha - 8) / 2048; i++)
  256. {
  257. uint8 alphamap[2048];
  258. buf.read((uint8*)alphamap,2048);
  259. if(mcal_compressed)
  260. {
  261. MCAL_decompress(alphamap,_chunks[mcnkid].alphamap[i]);
  262. }
  263. else
  264. {
  265. for(uint32 aly = 0; aly < 64; aly++)
  266. {
  267. for(uint32 alx = 0; alx < 32; alx++)
  268. {
  269. _chunks[mcnkid].alphamap[i][aly*64 + (alx*2)] = alphamap[aly*64 + alx] & 0xF0; // first 4 bits
  270. _chunks[mcnkid].alphamap[i][aly*64 + (alx*2)+1] = alphamap[aly*64 + alx] & 0x0F; // second
  271. }
  272. }
  273. }
  274. }
  275. }
  276. else if(!strcmp((char*)mfcc,"MCLQ")) // MCLQ changed to MH2O chunk for whole ADT file
  277. {
  278. uint8 _cc3[5];
  279. uint8 *fcc1 = &_cc3[0];
  280. buf.read(fcc1,4);
  281. flipcc(fcc1);
  282. fcc1[4]=0;
  283. if (!strcmp((char*)fcc1,"MCSE"))
  284. {
  285. _chunks[mcnkid].haswater = false;
  286. //DEBUG(printf("ADT: MCNK: MCLQ not present\n"));
  287. buf.rpos(buf.rpos()-4);
  288. continue; // next block read will be the MCSE block
  289. }
  290. else
  291. {
  292. _chunks[mcnkid].haswater = true;
  293. float tmp;
  294. buf.rpos(buf.rpos()-4);
  295. uint32 bufpos=buf.rpos();
  296. buf >> _chunks[mcnkid].waterlevel;
  297. buf >> tmp;
  298. //DEBUG(printf("ADT: MCNK: MCLQ base floats: %f %f\n",_chunks[mcnkid].waterlevel,tmp));
  299. //buf.rpos(buf.rpos()+4); // base height??
  300. if(msize > 8) // just to be sure
  301. {
  302. uint32 rbytes,diffbytes;
  303. for(uint32 i = 0; i < 81; i++)
  304. {
  305. _chunks[mcnkid].lqvertex[i] = buf.read<LiquidVertex>();
  306. }
  307. for(uint32 i = 0; i < 64; i++)
  308. {
  309. buf >> _chunks[mcnkid].lqflags[i];
  310. }
  311. rbytes = buf.rpos() - bufpos;
  312. DEBUG(printf("ADT: MCNK: MCLQ block loaded. %u / %u bytes.\n",rbytes,msize));
  313. // HACK: skip some unk junk bytes
  314. diffbytes = msize - rbytes; // difference should always be 84 (0x54) bytes
  315. buf.rpos(buf.rpos()+diffbytes);
  316. DEBUG(printf("ADT: MCNK: MCLQ - %u junk bytes skipped\n",diffbytes));
  317. }
  318. else
  319. {
  320. //DEBUG(printf("ADT: MCNK: MCLQ block has only %u bytes\n",msize));
  321. }
  322. }
  323. }
  324. else if(!strcmp((char*)mfcc,"MCSE"))
  325. {
  326. uint32 emm = _chunks[mcnkid].hdr.nSndEmitters;
  327. for(uint32 i = 0; i < emm; i++)
  328. {
  329. _soundemm.push_back(buf.read<MCSE_chunk>());
  330. }
  331. break;
  332. }
  333. else
  334. {
  335. //DEBUG(printf("ADT: MCNK: '%s' block unhandled, skipping %u bytes\n",mfcc,msize));
  336. if(!(isalnum(mfcc[0]) && isalnum(mfcc[1]) && isalnum(mfcc[2]) && isalnum(mfcc[3])))
  337. {
  338. printf("Error loading ADT file (chunk %u error).\n",mcnkid);
  339. return false;
  340. }
  341. buf.rpos(buf.rpos()+msize);
  342. }
  343. }
  344. mcnkid++;
  345. buf.rpos(endpos);
  346. }
  347. else
  348. {
  349. //DEBUG(printf("ADT: '%s' block unhandled, skipping %u bytes\n",fourcc,size));
  350. if(!(isalnum(fourcc[0]) && isalnum(fourcc[1]) && isalnum(fourcc[2]) && isalnum(fourcc[3])))
  351. {
  352. printf("Error loading ADT file.\n");
  353. return false;
  354. }
  355. buf.rpos(buf.rpos()+size);
  356. }
  357. }
  358. return true;
  359. }