1 魔兽争霸3的模型数据都被打包压缩在*.mpq里,可以通过SFmpq_static.lib提供的接口获取相应的数据段句柄(MPQHANDLE)。 2 读取MPQ时,首先要知道这个MPQ里有多少个被打了包的文件数目以及每个文件的名字,可以通过SFmpq_static.lib的SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile)接口查找数据段标记(TAG)为(listfile)在MPQ里的位置句柄,然后继续用接口获取到数据段长度后,将这段数据Read到内存里来,这些数据全是关于文件名及相对路径的字符串,接下来可以创建一个临时文件,把数据fwrite到这个临时文件里,这样就可以用fscan逐一读出文件名并保存起来了(比如保存成一个table)。 3 现在有了文件的索引了,在读取模型时,还是用SFileOpenFile获取这个模型在MPQ的句柄,然后再用接口读到内存,这样就可以专门针对这段模型数据段进行分析了。 下面是魔兽3的模型文件格式: MDLX -- 4个char,即4个字节一个DWORD的长度,这个是魔兽3模型格式的专用头标记,如果没有则表示出错 VERS -- 4个char,一个DWORD的长度,即4个字节 version data -- DWORD类型 实际的version数据 MODL -- 4个char 这个模型的属性数据,如boundingbox MODL size -- DWORD 在模型数据段中的长度,一般就是372的固定长度 MODL name1 -- 80个字节 MODL name2 -- 260个字节 MODL unknow float -- 4个字节,float类型 功能未知 MODL boundingbox min vector -- 3个float,12个字节 boundingbox min vector MODL boundingbox max vector -- 3个float,12个字节 MODL unknow DWORD -- 4个字节 ( 80+260+4+12+12+4=372 ) SEQS -- 4个字节 动作数据 SEQS size -- 4个字节 SEQS data -- 上面读出来的SEQS size个字节 ( 单个动作数据的struct: struct SequenceName { char mName[80]; int mUnk1; int mUnk2; float mUnk3; int mUnk4; float mUnk5; int mUnk6; float mUnk7; Vec3 mMins; Vec3 mMaxs; }; 动作的数量: mNumSequences = SEQS size / sizeof(SequenceName); ) unknow TAG -- 4个字节 unknow TAG size -- 4个字节 unknow TAG data -- unknow TAG size个字节 MTLS -- 4个字节 MTLS size -- 4个字节 MTLS data -- MTLS size个字节 ( class mdxMaterial { #define MAX_LAYER 8 public: int mUnk1; int mUnk2; // 'LAYS' int mNumLayers; Layer1 mLayers[MAX_LAYER]; ...... }; struct Layer1 { int mLayerSize; // in Bytes int mBlendMode; int mUnk3; int mTexture; int mUnk5; int mUnk6; float mUnk7; // alpha ? BOOL mKMTA; }; MTLS data里具体的材质数据读取是: 先读一个4个字节的单个mdxMaterial的size(layer1的数量不同导致mdxMaterial的大小不同),然后按照结构顺序填充,碰到layer1时,用同样的方法,先读4字节Layer1的size,然后按照顺序填充layer1,总共填充mNumLayers次 ) TEXS -- 4个字节 模型使用的贴图纹理数据 TEXS size -- 4个字节 ( struct Texture { DWORD mUnk1; char mName[MAX_PATH]; // 260 DWORD mUnk2; }; 由若干个Texture构成,Texture Numbers = TEXS size / sizeof(Texture) ) TEXS data -- TEXS size个字节 贴图纹理数据 GEOS -- 4个字节 GEOS size -- 4个字节 GEOS data -- GEOS size个字节 ( GEOS数据段由若干个mdxGeoChunk构成 单个mdxGeoChunk具体数据分布如下: VRTX -- 4个字节 number of vertex -- 4个字节 vertex data -- number of vertex * 12个字节 每个顶点占用3*4个字节 NRMS -- 4个字节 number of normals -- 4个字节 normal data -- number of normals * 12个字节 法线数据 PTYP -- 4个字节 primitives type PTYP size -- 4个字节 PTYP data -- PTYP size * 4个字节 PCNT -- 4个字节 primitives count PCNT size -- 4个字节 PCNT data -- PCNT size * 4个字节 PVTX -- 4个字节 primitives vertices 构成IB的primitive数据 PVTX size -- 4个字节 PVTX data -- PVTX size * 2个字节 ( struct Triangle { short ind[3]; }; PVTX data里含PVTX size*2/sizeof(Triangle)个Triangle ) GNDX -- 4个字节 vertex group indices GNDX size -- 4个字节 GNDX data -- GNDX size个字节 MTGC -- 4个字节 group matrix counts MTGC size -- 4个字节 MTGC data -- MTGC size*4个字节 MATS -- 4个字节 matrices MATS size -- 4个字节 MATS data -- MATS size*4个字节 unknow DWORD*4 -- 4*4个unknow DWORD chunk bounding box -- 2*3*4个字节 unknown struct number -- 4个字节 unknown struct data -- unknown struct number*(4+12*2)个字节 UVAS -- 4个字节 UVAS size -- 4个字节 UVBS -- 4个字节 UVBS size -- 4个字节 UVBS data -- UVBS size*8个字节 ) unknown TAG -- 4个字节 unknown TAG size -- 4个字节 unknown TAG data -- unknown TAG size个字节 BONE -- 4个字节 BONE size -- 4个字节 BONE data -- BONE size个字节 unknown TAG -- 4个字节 unknown TAG size -- 4个字节 unknown TAG data -- unknown TAG size个字节 重复上面的unkown TAG读取过程5遍 |