* found a problem with file listing, _startup.def refuses to load some .def files. trying to fix that now...
339 lines
12 KiB
C++
339 lines
12 KiB
C++
#include <fstream>
|
|
#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()<buf.size())
|
|
{
|
|
buf.read(fourcc,4); flipcc(fourcc);
|
|
buf.read((uint8*)&size,4);
|
|
//DEBUG(printf("ADT: reading '%s' size %u\n",fourcc,size));
|
|
|
|
if(!strcmp((char*)fourcc,"MVER"))
|
|
{
|
|
buf >> _version;
|
|
}
|
|
else if(!strcmp((char*)fourcc,"MHDR"))
|
|
{
|
|
mhdr = buf.read<MHDR_chunk>();
|
|
}
|
|
else if(!strcmp((char*)fourcc,"MCIN"))
|
|
{
|
|
for(uint32 i = 0; i < CHUNKS_PER_TILE; i++)
|
|
{
|
|
mcin[i] = buf.read<MCIN_chunk>();
|
|
//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<ndoodads; i++)
|
|
{
|
|
_doodadsp.push_back(buf.read<MDDF_chunk>());
|
|
}
|
|
}
|
|
else if(!strcmp((char*)fourcc,"MODF"))
|
|
{
|
|
uint32 nwmos = size / 64;
|
|
//DEBUG(printf("ADT: Loading %u wmos.\n",nwmos));
|
|
for(uint32 i = 0; i<nwmos; i++)
|
|
{
|
|
_wmosp.push_back(buf.read<MODF_chunk>());
|
|
}
|
|
}
|
|
else if(!strcmp((char*)fourcc,"MCNK"))
|
|
{
|
|
_chunks[mcnkid].hdr = buf.read<ADTMapChunkHeader>();
|
|
uint8 *mfcc = new uint8[5]; mfcc[4]=0;
|
|
uint32 msize;
|
|
while(buf.rpos()<buf.size())
|
|
{
|
|
buf.read(mfcc,4); flipcc(mfcc);
|
|
buf.read((uint8*)&msize,4);
|
|
|
|
// HACKS to make it work properly
|
|
if(!msize && !strcmp((char*)mfcc,"MCAL"))
|
|
continue;
|
|
if((!msize) && !strcmp((char*)mfcc,"MCLQ"))
|
|
msize = _chunks[mcnkid].hdr.sizeLiquid;
|
|
|
|
//DEBUG(printf("ADT: MCNK: reading '%s' size %u\n",mfcc,msize));
|
|
|
|
if(!strcmp((char*)mfcc,"MCVT"))
|
|
{
|
|
for(uint32 i = 0; i < 145; i++)
|
|
{
|
|
buf >>_chunks[mcnkid].vertices[i];
|
|
}
|
|
}
|
|
else if(!strcmp((char*)mfcc,"MCNR"))
|
|
{
|
|
for(uint32 i = 0; i < 145; i++)
|
|
{
|
|
_chunks[mcnkid].normalvecs[i] = buf.read<NormalVector>();
|
|
}
|
|
// 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<MCLY_chunk>();
|
|
}
|
|
}
|
|
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<LiquidVertex>();
|
|
}
|
|
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<MCSE_chunk>());
|
|
}
|
|
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<std::string>& 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<std::string>& st)
|
|
{
|
|
ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM");
|
|
}
|
|
|
|
void ADT_FillWMOData(const uint8* data,std::set<std::string>& st)
|
|
{
|
|
ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM");
|
|
}
|
|
|
|
void ADT_FillModelData(const uint8* data,std::set<std::string>& st)
|
|
{
|
|
ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM");
|
|
}
|