天天看点

【分析】魔兽争霸3的MPQ文件及模型格式分析

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遍

继续阅读