ADT/v18

From wowdev
Jump to navigation Jump to search

Retrived from; http://wowdev.org/wiki/index.php/ADT


ADT Files

ADT files contain terrain and object information for map tiles. They have a chunked structure just like the WDT files.

A map tile is split up into 16x16 = 256 map chunks. (not the same as file chunks, although each map chunk will have its own file chunk :) ) So there will be a few initial data chunks to specify textures, objects, models, etc. followed by 256 MCNK (mapchunk) chunks :) Each MCNK chunk has a small header of its own, and additional chunks within its data block, following the same id-size-data format.


MHDR chunk

struct SMAreaHeader // 03-29-2005 By ObscuR
{
/*000h*/  UINT32 pad;
/*004h*/  UINT32 offsInfo;		
/*008h*/  UINT32 offsTex;		
/*00Ch*/  UINT32 offsModels;		
/*010h*/  UINT32 offsModelsIds;		
/*014h*/  UINT32 offsMapObejcts;		
/*018h*/  UINT32 offsMapObejctsIds;		
/*01Ch*/  UINT32 offsDoodsDef;		
/*020h*/  UINT32 offsObjectsDef;	
/*024h*/  UINT32 pad1;	
/*028h*/  UINT32 pad2;		
/*02Ch*/  UINT32 pad3;	
/*030h*/  UINT32 pad4;		
/*034h*/  UINT32 pad5;		
/*038h*/  UINT32 pad6;		
/*03Ch*/  UINT32 pad7;	
/*040h*/
};

Header chunk. Contains offsets (relative to 0x14) for some other chunks that appear in the file. Since the file follows a well-defined structure, this is redundant information.

MCIN chunk

Index for MCNK chunks. Contains 256 records of 16 bytes, which have the following format:


Offset	Type		Description
0x0	uint32		MCNK chunk absolute offset
0x4	uint32		MCNK size in bytes
0x8	8 bytes		0


struct SMChunkInfo // 03-29-2005 By ObscuR
{
/*000h*/  UINT32 offset;
/*004h*/  UINT32 size;		
/*008h*/  UINT32 flags;		
/*00Ch*/  UINT32 asyncId;;		
/*010h*/  		
};

This is also redundant information but kind of convenient.

MTEX chunk

List of textures used by the terrain in this map tile. A contiguous block of zero-terminated strings, that are complete filenames with paths. The textures will later be identified by their position in this list.


MMDX chunk

List of filenames for M2 models that appear in this map tile. A contiguous block of zero-terminated strings.


MMID chunk

Lists the relative offsets of string beginnings in the above MMDX chunk. (sort of redundant) One 32-bit integer per offset.


MWMO chunk

List of filenames for WMOs (world map objects) that appear in this map tile. A contiguous block of zero-terminated strings.


MWID chunk

Lists the relative offsets of string beginnings in the above MWID chunk. (again, redundant) One 32-bit integer per offset.


MDDF chunk

Placement information for doodads (M2 models). 36 bytes per model instance.

Offset 	Type 	Description
0x00 	uint32 	ID (index in the MMDX list)
0x04 	uint32 	unique identifier for this instance
0x08 	3 floats 	Position (X,Y,Z)
0x14 	3 floats 	Orientation (A,B,C)
0x20 	uint32 	scale factor * 1024
struct SMDoodadDef // 03-31-2005 By ObscuR
{
/*000h*/  UINT32 nameId;
/*004h*/  UINT32 uniqueId;		
/*008h*/  float pos[3];		
/*00Ch*/ 
/*010h*/ 
/*014h*/  float rot[3];		
/*018h*/  		
/*01Ch*/  		
/*020h*/  UINT16 flags;	
/*022h*/  UINT16 scale;
/*024h*/  
};

The instance information specifies the actual M2 model to use, its absolute position and orientation within the world. The orientation is defined by rotations (in degrees) about the 3 axes as such (this order of operations is for OpenGL, so the transformations "actually" happen in reverse):

  1. Rotate around the Y axis by B-90
  2. Rotate around the Z axis by -A
  3. Rotate around the X axis by C 

Finally the scale factor is given by an integer, multiplied by 1024. So the model needs to be scaled by scale/1024. I wonder why they didn't just use a float.


MODF chunk

Placement information for WMOs. 64 bytes per wmo instance.

Offset 	Type 	Description
0x00 	uint32 	ID (index in the MWMO list)
0x04 	uint32 	unique identifier for this instance
0x08 	3 floats 	Position (X,Y,Z)
0x14 	3 floats 	Orientation (A,B,C)
0x20 	3 floats 	Position 2 - ?
0x2C 	3 floats 	Position 3 - ?
0x38 	uint16 	unknown (always 0?)
0x3A 	uint16 	Doodad set index
0x3C 	uint32 	Name set
struct SMMapObjDef // 03-29-2005 By ObscuR
{
/*000h*/  UINT32 nameId;		
/*004h*/  UINT32 uniqueId;		
/*008h*/  float pos[3];
/*00Ch*/  		
/*010h*/  		
/*014h*/  float rot[3];
/*018h*/  	
/*01Ch*/  		
/*020h*/  float extents[6];
/*024h*/  	 
/*028h*/   	
/*02Ch*/ 	
/*030h*/ 		
/*034h*/  		
/*038h*/  UINT32 flags;		
/*03Ch*/  UINT16 doodadSet;
/*03Eh*/  UINT16 nameSet;
/*040h*/ 
}; 

The positioning and orientation is done the same way as in the MDDF chunk. There is no scaling. Two additional positions and two integers are also given. They might or might not be used for lighting...?

The unique identifier is important for WMOs, because multiple map tiles might want to draw the same WMO. This identifier is used to ensure that each specific instance can only be drawn once. (a unique identifier is required because the model name is not usable for this purpose, since it is possible to have more than one instance of the same WMO, like some bridges in Darkshore)


MCNK chunks

After the above mentioned chunks come 256 individual MCNK chunks, row by row, starting from top-left (northwest). The MCNK chunks have a large block of data that starts with a header, and then has sub-chunks of its own.

Each map chunk has 9x9 vertices, and in between them 8x8 additional vertices, several texture layers, normal vectors, a shadow map, etc.

The MCNK header is 128 bytes large. I will only list the known fields in the header.

Offset 	 Type 	 Description
0x3C 	uint32 	holes in terrain
0x68 	float 	Z' base coordinate
0x6C 	float 	X' base coordinate
0x70 	float 	Y base coordinate
struct SMChunk // 03-29-2005 By ObscuR
{
	enum 
	{
		FLAG_SHADOW,
		FLAG_IMPASS,
 		FLAG_LQ_RIVER,
		FLAG_LQ_OCEAN,
		FLAG_LQ_MAGMA,
	};
/*000h*/  UINT32 flags;
/*004h*/  UINT32 IndexX;
/*008h*/  UINT32 IndexY;
/*00Ch*/  UINT32 nLayers;
/*010h*/  UINT32 nDoodadRefs;
/*014h*/  UINT32 offsHeight;
/*018h*/  UINT32 offsNormal;
/*01Ch*/  UINT32 offsLayer;
/*020h*/  UINT32 offsRefs;
/*024h*/  UINT32 offsAlpha;
/*028h*/  UINT32 sizeAlpha;
/*02Ch*/  UINT32 offsShadow;
/*030h*/  UINT32 sizeShadow;
/*034h*/  UINT32 areaid;
/*038h*/  UINT32 nMapObjRefs;
/*03Ch*/  UINT32 holes;
/*040h*/  UINT16 unk1;
/*040h*/  UINT16 unk2;
/*044h*/  UINT32 unk3;
/*048h*/  UINT32 unk4;
/*04Ch*/  UINT32 unk5;
/*050h*/  UINT32 predTex;
/*054h*/  UINT32 noEffectDoodad;
/*058h*/  UINT32 offsSndEmitters;
/*05Ch*/  UINT32 nSndEmitters;
/*060h*/  UINT32 offsLiquid;
/*064h*/  UINT32 sizeLiquid;
/*068h*/  float  pos[3];
/*06Ch*/  
/*070h*/ 
/*074h*/  UINT32 textureId;
/*078h*/  UINT32 props;
/*07Ch*/  UINT32 effectId;
/*080h*/
};

The X' and Z' coordinates specify the top left corner of the map chunk, but they are in an alternate coordinate system! (yay for consistency!) This one has its 0,0 point in the middle of the world, and has the axes' directions reversed.

X = 32*533.3333 - X'

Z = 32*533.3333 - Z'

The Y base coordinate acts as a 'zero point' for the height values in the upcoming height map - that is, all height values are added to this Y height.

About the holes in the terrain: This is a bitmapped field, the least significant 16 bits are used row-wise in the following arrangement with a 1 bit meaning that the map chunk has a hole in that part of its area:

0x1 	0x2 	0x4 	0x8
0x10 	0x20 	0x40 	0x80
0x100 	0x200 	0x400 	0x800
0x1000 	0x2000 	0x4000 	0x8000

With this I've been able to fix some holes, the most obvious one being the Gates of Ironforge but there are some glitches for some other holes like the Lakeshire Inn - maybe this would require the more detailed height maps or for me to use a less cheap way to omit the hole triangles. :)