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遍