#include #include "common.h" #include "ADTFile.h" inline void flipcc(uint8 *fcc) { char t; t=fcc[0]; fcc[0]=fcc[3]; fcc[3]=t; t=fcc[1]; fcc[1]=fcc[2]; fcc[2]=t; } bool ADTFile::Load(std::string fn) { uint32 fs = GetFileSize(fn.c_str()); if(!fs) return false; std::fstream fh; fh.open(fn.c_str(), std::ios_base::in | std::ios_base::binary); if(!fh.is_open()) return false; ByteBuffer buf(fs); buf.resize(fs); fh.read((char*)buf.contents(),fs); fh.close(); buf.rpos(0); return LoadMem(buf); } bool ADTFile::LoadMem(ByteBuffer& buf) { uint32 texturecnt=0,modelcnt=0,wmocnt=0; uint32 size; // used for every chunk uint32 mcnkid=0; uint8 *fourcc = new uint8[5]; fourcc[4]=0; while(buf.rpos()> _version; } else if(!strcmp((char*)fourcc,"MHDR")) { mhdr = buf.read(); } else if(!strcmp((char*)fourcc,"MCIN")) { for(uint32 i = 0; i < CHUNKS_PER_TILE; i++) { mcin[i] = buf.read(); //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)); if(!mcin[i].offset) { printf("ADT: ERROR: chunk offset is NULL! Not loading.\n"); return false; } } } else if(!strcmp((char*)fourcc,"MTEX")) { for(uint32 i=0;;i++) { std::string tex; memcpy(fourcc,buf.contents()+buf.rpos(),4); flipcc(fourcc); if(!memcmp(fourcc,"MMDX",4)) break; buf >> tex; //DEBUG(printf("MTEX offset %u \"%s\"\n",buf.rpos(),tex.c_str())); _textures.push_back(tex); texturecnt++; } //DEBUG(printf("ADT: loaded %u textures\n",texturecnt)); } else if(!strcmp((char*)fourcc,"MMDX")) { for(uint32 i=0;;i++) { std::string model; memcpy(fourcc,buf.contents()+buf.rpos(),4); flipcc(fourcc); if(!memcmp(fourcc,"MMID",4)) break; buf >> model; //DEBUG(printf("MMDX offset %u \"%s\"\n",buf.rpos(),model.c_str())); _models.push_back(model); modelcnt++; } //DEBUG(printf("ADT: loaded %u models\n",modelcnt)); } /*else if(!strcmp((char*)fourcc,"MMID")) { for(uint32 i = 0; i <= modelcnt; i++) { uint32 offs; buf >> offs; // we dont really need those offsets } }*/ else if(!strcmp((char*)fourcc,"MWMO")) { for(uint32 i=0;;i++) { std::string wmo; memcpy(fourcc,buf.contents()+buf.rpos(),4); flipcc(fourcc); if(!memcmp(fourcc,"MWID",4)) break; buf >> wmo; //DEBUG(printf("MWMO offset %u \"%s\"\n",buf.rpos(),wmo.c_str())); _wmos.push_back(wmo); wmocnt++; } } /*else if(!strcmp((char*)fourcc,"MWID")) { for(uint32 i = 0; i <= wmocnt; i++) { uint32 offs; buf >> offs; // we dont really need those offsets } }*/ else if(!strcmp((char*)fourcc,"MDDF")) { uint32 ndoodads = size / 36; //DEBUG(printf("ADT: Loading %u doodads.\n",ndoodads)); for(uint32 i = 0; i()); } } else if(!strcmp((char*)fourcc,"MODF")) { uint32 nwmos = size / 64; //DEBUG(printf("ADT: Loading %u wmos.\n",nwmos)); for(uint32 i = 0; i()); } } else if(!strcmp((char*)fourcc,"MCNK")) { _chunks[mcnkid].hdr = buf.read(); uint8 *mfcc = new uint8[5]; mfcc[4]=0; uint32 msize; while(buf.rpos()>_chunks[mcnkid].vertices[i]; } } else if(!strcmp((char*)mfcc,"MCNR")) { for(uint32 i = 0; i < 145; i++) { _chunks[mcnkid].normalvecs[i] = buf.read(); } // HACK: skip unk junk bytes if(msize==0x1B3) buf.rpos(buf.rpos()+0xD); } else if(!strcmp((char*)mfcc,"MCLY")) { _chunks[mcnkid].nTextures = msize / 16; ASSERT(msize/16 == _chunks[mcnkid].hdr.nLayers); for(uint32 i = 0; i < _chunks[mcnkid].nTextures; i++) { _chunks[mcnkid].layer[i] = buf.read(); } } else if(!strcmp((char*)mfcc,"MCSH")) { buf.read((uint8*)&(_chunks[mcnkid].shadowmap),512); } else if(!strcmp((char*)mfcc,"MCAL")) { for(uint32 i = 0; i < (_chunks[mcnkid].hdr.sizeAlpha - 8) / 2048; i++) { buf.read((uint8*)(_chunks[mcnkid].alphamap[i]),2048); } } else if(!strcmp((char*)mfcc,"MCLQ")) { uint8 *fcc1 = new uint8[5]; buf.read(fcc1,4); flipcc(fcc1); fcc1[4]=0; if (!strcmp((char*)fcc1,"MCSE")) { _chunks[mcnkid].haswater = false; //DEBUG(printf("ADT: MCNK: MCLQ not present\n")); buf.rpos(buf.rpos()-4); delete [] fcc1; continue; // next block read will be the MCSE block } else { _chunks[mcnkid].haswater = true; float tmp; buf.rpos(buf.rpos()-4); uint32 bufpos=buf.rpos(); uint32 rbytes,diffbytes; buf >> _chunks[mcnkid].waterlevel; buf >> tmp; //DEBUG(printf("ADT: MCNK: MCLQ base floats: %f %f\n",_chunks[mcnkid].waterlevel,tmp)); //buf.rpos(buf.rpos()+4); // base height?? if(msize > 8) // just to be sure { for(uint32 i = 0; i < 81; i++) { _chunks[mcnkid].lqvertex[i] = buf.read(); } for(uint32 i = 0; i < 64; i++) { buf >> _chunks[mcnkid].lqflags[i]; } rbytes = buf.rpos() - bufpos; //DEBUG(printf("ADT: MCNK: MCLQ block loaded. %u / %u bytes.\n",rbytes,msize)); } else { //DEBUG(printf("ADT: MCNK: MCLQ block has only %u bytes\n",msize)); } // HACK: skip some unk junk bytes diffbytes = (msize-8) - rbytes; // dont forget to skip the 8 initial bytes buf.rpos(buf.rpos()+diffbytes); //DEBUG(printf("ADT: MCNK: MCLQ - %u junk bytes skipped\n",diffbytes)); delete [] fcc1; } } else if(!strcmp((char*)mfcc,"MCSE")) { uint32 emm = _chunks[mcnkid].hdr.nSndEmitters; for(uint32 i = 0; i < emm; i++) { _soundemm.push_back(buf.read()); } break; } else { //DEBUG(printf("ADT: MCNK: '%s' block unhandled, skipping %u bytes\n",mfcc,msize)); if(!(isalnum(mfcc[0]) && isalnum(mfcc[1]) && isalnum(mfcc[2]) && isalnum(mfcc[3]))) { printf("Error loading ADT file (chunk %u error).\n",mcnkid); return false; // dont care about those few mem leaks } buf.rpos(buf.rpos()+msize); } } delete [] mfcc; mcnkid++; } else { //DEBUG(printf("ADT: '%s' block unhandled, skipping %u bytes\n",fourcc,size)); if(!(isalnum(fourcc[0]) && isalnum(fourcc[1]) && isalnum(fourcc[2]) && isalnum(fourcc[3]))) { printf("Error loading ADT file.\n"); return false; // dont care about those few mem leaks } buf.rpos(buf.rpos()+size); } } delete [] fourcc; return true; } void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set& st, char* stop) { data += ((uint32*)data)[off]; // seek to correct absolute offset data += 28; // move ptr to real start of data uint32 offset=0; std::string s; char c; while(memcmp(data+offset,stop,4)) { c = data[offset]; if(!c) { if(s.length()) { DEBUG(printf("DEP: %s\n",s.c_str())); st.insert(s); s.clear(); } } else s += c; offset++; } } void ADT_FillTextureData(const uint8* data,std::set& st) { ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM"); } void ADT_FillWMOData(const uint8* data,std::set& st) { ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM"); } void ADT_FillModelData(const uint8* data,std::set& st) { ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM"); }