天天看點

【分析】魔獸争霸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遍

繼續閱讀