MDL

From GTAModding
Jump to: navigation, search

MDL is the model format for the Stories games. They are the relocatable chunk version of Rsl DFF files after they have been preprocessed by their respective ModelInfo class. Hence the format differs for different types of ModelInfos and also for each platform and game. The structures below are for the PS2 files. Mobile LCS doesn't make use of mdl files but still has the code to read and write them.

For the most part the structures are almost the same as their RW counterparts. The actual geometry however is most notably different. The DFF files from mobile LCS contain PS2 geometry that is converted to OpenGL geometry at runtime.

The main structure at the beginning of the data depends on the ModelInfo type:

struct SimpleModel
{
	RslElement *element[N];
};

Where N is the number of Elements (Atomics) of the object (stored in ModelInfo).

struct ElementGroupModel
{
	RslElementGroup *elementgroup;
};
struct PedModel
{
	CColModel *colModel;
	RslElementGroup *elementgroup;
};
struct VehicleModel
{
	RslElementGroup *elementgroup;
	int32 numExtras;
	RslElement **extras;
	RslMaterial *primaryMaterials[NUMPRIM];
	RslMaterial *secondaryMaterials[NUMSEC];
};

Where NUMPRIM and NUMSEC are 25 in LCS and 30 and 25 respectively in VCS.

The Rsl structures are:

struct RslV3
{
	float32 x, y, z;
};

struct RslMatrix
{
	RslV3 right;
	uint32 flags;
	RslV3 up;
	uint32 pad1;
	RslV3 at;
	uint32 pad2;
	RslV3 pos;
	uint32 pad3;
};

struct RslLLLink
{
	RslLLLink *next;
	RslLLLink *prev;
};

struct RslLinkList
{
	RslLLLink link;
};

struct RslObject {
	uint8  type;
	uint8  subType;
	uint8  flags;
	uint8  privateFlags;
	void  *parent;
};

struct RslObjectHasNode {
	RslObject   object;
	RslLLLink   lNode;
	void      (*sync)();
};

struct RslRasterPS2 {
	uint8 *data;
	uint32 flags;
};

struct RslRasterPSP {
	uint32 unk1;
	uint8 *data;
	uint16 flags1;
	uint8  width;    // log of width
	uint8  height;   // log of height
	uint32 flags2;
};

struct RslPs2StreamRaster {
	uint32 width;
	uint32 height;
	uint32 depth;
	uint32 mipmaps;
	uint32 unused;
};

union RslRaster {
	RslRasterPS2 ps2;
	RslRasterPSP psp;
};

struct RslTexList {
	RslObject   object;
	RslLinkList texturesInDict;
	RslLLLink   lInInstance;
};

struct RslTexture {
	RslRaster        *raster;
	RslTexList       *dict;
	RslLLLink         lInDictionary;
	char              name[32];
	char              mask[32];
};

struct RslNode {
	RslObject         object;
	RslLinkList       objectList;
		         
	RslMatrix         modelling;
	RslMatrix         ltm;
	RslNode          *child;
	RslNode          *next;
	RslNode          *root;

	// RwHAnimNodeExtension
#ifdef LCS
	int32              nodeId;
#else
	int32		   unknown1;
	int32		   unknown2;
#endif
	RslTAnimTree      *hier;
	// R* Node name
	char              *name;
	// R* Visibility
	int32              hierId;
};

struct rslNodeList
{
	RslNode **frames;
	int32 numNodes;
};

struct RslElementGroup {
	RslObject   object;
	RslLinkList atomicList;
};

struct RslElement {
	RslObjectHasNode          object;
	RslGeometry              *geometry;
	RslElementGroup          *clump;
	RslLLLink                 inElementGroupLink;

	RslElementCallBackRender  renderCallBack;
	// CVisibilityComponents
	int16                     modelInfoId;
	uint16                    visIdFlag;
	// RpSkin              
	RslTAnimTree             *hier;
};

struct RslMaterialList {
	RslMaterial **materials;
	int32         numMaterials;
	int32         space;
};

struct RslGeometry {
	RslObject       object;
	int16           refCount;
	int16           pad1;

	RslMaterialList matList;

	RslSkin        *skin;
};

struct RslMatFXEnv {
	RslNode *frame;
	union {
		char       *texname;
		RslTexture *texture;
	};
	float32   intensity;
};

struct RslMatFX {
	union {
		RslMatFXEnv env;
	};
	int32     effectType;
};

struct RslMaterial {
	union {
		char       *texname;
		RslTexture *texture;
	};
	RGBA        color;
	uint32      refCount;
	RslMatFX   *matfx;
};

struct RslTAnimNodeInfo {
	int8      id;
	int8      index;
	int8      flags;
	RslNode  *frame;
};

struct RslTAnimTree {
	int32              flags;
	int32              numNodes;
	void              *pCurrentAnim;
	float32            currentTime;
	void              *pNextFrame;
	void             (*pAnimCallBack)();
	void              *pAnimCallBackData;
	float32            animCallBackTime;
	void             (*pAnimLoopCallBack)();
	void              *pAnimLoopCallBackData;
	float32           *pMatrixArray;
	void              *pMatrixArrayUnaligned;
	RslTAnimNodeInfo  *pNodeInfo;
#ifdef LCS
	RslNode           *parentNode;
	int32              maxKeyFrameSize;
	int32              currentKeyFrameSize;
	void             (*keyFrameToMatrixCB)();
	void             (*keyFrameBlendCB)();
	void             (*keyFrameInterpolateCB)();
	void             (*keyFrameAddCB)();
	RslTAnimTree      *parentTree;
	int32              offsetInParent;
	int32              rootParentOffset;
#endif
};

struct RslSkin {
	uint32   numBones;
	uint32   numUsedBones;	// == numBones
	uint8   *usedBones;	// NULL
	float32 *invMatrices;
	int32    numWeights;	// 0
	uint8   *indices;	// NULL
	float32 *weights;	// NULL
	uint32   unk1;          // 0
	uint32   unk2;          // 0
	uint32   unk3;          // 0
	uint32   unk4;          // 0
	uint32   unk5;          // 0
	void    *data;          // NULL
};

struct sPs2Geometry {
	float32 bound[4];
	uint32  size;		// and numMeshes
	int32   flags;
	uint32  unk1;
	uint32  unk2;
	uint32  unk3;
	uint32  unk4;
	float32 scale[3];
	float32 pos[3];
};

struct sPs2GeometryMesh {
	float32  bound[4];
	float32  uvScale[2];
	int32    unknown;
	uint32   dmaPacket;
	uint16   numTriangles;
	int16    matID;
	int16    min[3];          // bounding box
	int16    max[3];
};

TODO: describe the geometry format.

In the file, textures are just file names. After loading they are replaced by actual RslTexture structs.

Tool

External link