diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj index 268f084..fd5b311 100644 --- a/src/PseuWoW.vcproj +++ b/src/PseuWoW.vcproj @@ -379,6 +379,28 @@ + + + + + + + + + + + + + + + + + + + + +#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()); + if(!fh.is_open()) + return false; + + ByteBuffer buf(fs); + buf.resize(fs); + fh.read((char*)buf.contents(),fs); + fh.close(); + + LoadMem(buf); + return m_loaded; +} + +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)); + } + } + 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++; + } + } + 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++; + } + } + /*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(strcmp((char*)mfcc,"MCRF")) + { + 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(strcmp((char*)fourcc,"MWID") && strcmp((char*)fourcc,"MMID")) + { + printf("Error loading ADT file.\n"); + return false; // dont care about those few mem leaks + } + buf.rpos(buf.rpos()+size); + } + + } + delete [] fourcc; + + + m_loaded = true; + return true; +} diff --git a/src/shared/ADTFile.h b/src/shared/ADTFile.h new file mode 100644 index 0000000..743eccb --- /dev/null +++ b/src/shared/ADTFile.h @@ -0,0 +1,30 @@ +#ifndef ADTFILE_H +#define ADTFILE_H + +#define CHUNKS_PER_TILE 256 + +#include "ADTFileStructs.h" + +class ADTFile +{ +public: + bool Load(std::string); + bool LoadMem(ByteBuffer&); + bool Loaded(void) { return m_loaded; } + + MapChunk _chunks[CHUNKS_PER_TILE]; // 16x16 + std::vector _textures; + std::vector _wmos; + std::vector _models; + std::vector _doodadsp; + std::vector _wmosp; + std::vector _soundemm; + MHDR_chunk mhdr; + MCIN_chunk mcin[CHUNKS_PER_TILE]; + uint32 _version; + + bool m_loaded; +}; + + +#endif diff --git a/src/shared/ADTFileStructs.h b/src/shared/ADTFileStructs.h new file mode 100644 index 0000000..e26564f --- /dev/null +++ b/src/shared/ADTFileStructs.h @@ -0,0 +1,208 @@ +// all credit for this file goes to the guys who write the wiki article about ADT files @ wowdev.org + +#ifndef ADTFILESTRUCTS_H +#define ADTFILESTRUCTS_H + +struct MHDR_chunk +{ + uint32 pad; + uint32 offsInfo; + uint32 offsTex; + uint32 offsModels; + uint32 offsModelsIds; + uint32 offsMapObejcts; + uint32 offsMapObejctsIds; + uint32 offsDoodsDef; + uint32 offsObjectsDef; + uint32 pad1; + uint32 pad2; + uint32 pad3; + uint32 pad4; + uint32 pad5; + uint32 pad6; + uint32 pad7; +}; + +struct MCIN_chunk +{ + uint32 offset; + uint32 size; + uint32 flags; + uint32 async; +}; + +// MTEX: texture filename list. strings only! + +// MMDX: M2 models filename list. strings only! + +// MMID: string start offset list of the MMDX block + +// MWMO: filename list for WMOs + +// MWID: string start offset list of the MWMO block + +struct MDDF_chunk +{ + uint32 id; // position in the MMDX list + uint32 uniqueid; // unique instance id (?) + float x; + float y; + float z; + float oy; + float oz; + float ox; + uint16 flags; + uint16 scale; +}; + +struct MODF_chunk +{ + uint32 id; + uint32 uniqueid; + float x; + float y; + float z; + float oy; + float oz; + float ox; + // unk floats (orientation?) + float ou11; + float ou12; + float ou13; + float ou21; + float ou22; + float ou23; + uint32 flags; + uint16 doodadSet; + uint16 nameSet; +}; + +enum MapChunkHeaderFlags +{ + FLAG_SHADOW, + FLAG_IMPASS, + FLAG_LQ_RIVER, + FLAG_LQ_OCEAN, + FLAG_LQ_MAGMA, +}; + +struct MapChunkHeader +{ + uint32 flags; + uint32 IndexX; + uint32 IndexY; + uint32 nLayers; + uint32 nDoodadRefs; + uint32 offsHeight; + uint32 offsNormal; + uint32 offsLayer; + uint32 offsRefs; + uint32 offsAlpha; + uint32 sizeAlpha; + uint32 offsShadow; + uint32 sizeShadow; + uint32 areaid; + uint32 nMapObjRefs; + uint32 holes; + uint16 unk1; + uint16 unk2; + uint32 unk3; + uint32 unk4; + uint32 unk5; + uint32 predTex; + uint32 noEffectDoodad; + uint32 offsSndEmitters; + uint32 nSndEmitters; + uint32 offsLiquid; + uint32 sizeLiquid; // includes the 8 initinal bytes ("MCLQ" and size) + float xbase; + float ybase; + float zbase; + uint32 textureId; + uint32 props; + uint32 effectId; +}; + +// MCNK sub-chunk +// 9x9+8x8 vertices. 145 floats, format: 9 outer, 8 inner, 9 outer, 8 inner, ... , 9 outer. + +// MCNR chunk: Normal vectors for each vertex, encoded as 3 signed bytes per normal, in the same order as specified above. + +struct MCLY_chunk +{ + uint32 textureId; // offset in MTEX list + uint32 flags; // 0x100 means using alpha map + uint32 offAlpha; + uint32 effectId; //detail texture id (?) +}; + +// MCRF chunk: +// A list of indices into the parent file's MDDF chunk, +// saying which MCNK subchunk those particular MDDF doodads are drawn within. +// This MCRF list contains duplicates for map doodads that overlap areas. +// But I guess that's what the MDDF's UniqueID field is for. + +// MCSH chunk: 8x8 bytes (64x64 bits) shadow map + + + + + +struct MCSE_chunk +{ + uint32 soundPointID; + uint32 soundNameID; + float x; + float y; + float z; + float minDistance; + float maxDistance; + float cutoffDistance; + uint16 startTime; + uint16 endTime; + uint16 groupSilenceMin; + uint16 groupSilenceMax; + uint16 playInstancesMin; + uint16 playInstancesMax; + uint16 loopCountMin; + uint16 loopCountMax; + uint16 interSoundGapMin; + uint16 interSoundGapMax; +}; + +struct LiquidVertex +{ + uint16 unk1; + uint16 unk2; + float h; +}; + +struct NormalVector +{ + uint8 x; + uint8 y; + uint8 z; +}; + +// also known as MCNK block +// 256 per adt file +struct MapChunk +{ + MapChunkHeader hdr; + float vertices[145]; + NormalVector normalvecs[145]; + MCLY_chunk layer[4]; // can be less + uint32 nTextures; + uint8 shadowmap[512]; // 1 bit 64x64 + uint8 alphamap[4][2048]; // 4 bits, 64x64. max 4, 1 per layer + bool haswater; + float waterlevel; + LiquidVertex lqvertex[81]; + uint8 lqflags[64]; + + + + +}; + +#endif \ No newline at end of file diff --git a/src/shared/tools.cpp b/src/shared/tools.cpp index c271eee..018e674 100644 --- a/src/shared/tools.cpp +++ b/src/shared/tools.cpp @@ -185,4 +185,15 @@ uint32 getMSTime(void) return time_in_ms; } +uint32 GetFileSize(const char* sFileName) +{ + std::ifstream f; + f.open(sFileName, std::ios_base::binary | std::ios_base::in); + if (!f.good() || f.eof() || !f.is_open()) { return 0; } + f.seekg(0, std::ios_base::beg); + std::ifstream::pos_type begin_pos = f.tellg(); + f.seekg(0, std::ios_base::end); + return f.tellg() - begin_pos; +} + diff --git a/src/shared/tools.h b/src/shared/tools.h index 839046a..364ecb4 100644 --- a/src/shared/tools.h +++ b/src/shared/tools.h @@ -19,5 +19,6 @@ std::deque GetFileList(std::string); bool FileExists(std::string); bool CreateDir(const char*); uint32 getMSTime(void); +uint32 GetFileSize(const char*); #endif \ No newline at end of file diff --git a/src/tools/stuffextract/StuffExtract.cpp b/src/tools/stuffextract/StuffExtract.cpp index 755b2d1..4f656be 100644 --- a/src/tools/stuffextract/StuffExtract.cpp +++ b/src/tools/stuffextract/StuffExtract.cpp @@ -3,6 +3,7 @@ #include "common.h" #include "MPQHelper.h" #include "dbcfile.h" +#include "ADTFile.h" #include "StuffExtract.h" #include "DBCFieldData.h" #include "Locale.h" @@ -268,6 +269,9 @@ void ExtractMaps(void) } fh.write((char*)bb.contents(),bb.size()); fh.close(); + ADTFile *adt = new ADTFile(); + adt->LoadMem(bb); + delete adt; extr++; } } @@ -280,3 +284,8 @@ void ExtractMaps(void) printf("\nDONE - %u maps extracted.\n",extrtotal); } + +void DoNothingDummy(void) +{ + delete [] new uint8[50]; +}