TR WAD FILE FORMAT

Document Version 1.0
By Turbo Pascal, Tegucigalpa, Honduras, Central America
                      December 11 - 2001

This document describe the file format used in a Tomb Raider WAD file used for the oficial level editor, currently i am only describing the sections that are used for my program Strpix3, so severals other section are not full described yet.
The file format is explained in sequential way, the red field show the data, next it come the size in bytes, also i am including a explanation on what it mean and how to use the field.
 

WAD file format

* Version : (4 bytes).   if 129 then this is a valid tomb Raider WAD file format.
//next come the texture table, first the amount texture pieces in this wad and later each texture piece definition.
* Amount_textures: (4 Bytes), amount textures pieces defined.
* Texture_records: (amount_textures*8 sizes bytes);
// all textures pieces are stored in  severals 256x256 pixels pages size .
// The texture record tell to the engine in wich page each texture piece is located and wich size in pixels they have.

// Each texture piece  record is 8 bytes size defined in the follow way:

  -  X1   : (1 Byte);
  -  Y1   : (1 Byte);
  -  PAGE : (2 bytes); //in which page the texture piece is stored.
  -  flipx: ( 1 Byte) ; // Normaly -1 or 0.
  -  width: (1  Byte); // Width for this texture (X2=X1+WIDTH)
  -  flipy: (1 Byte); // Normaly -1 or 0
  -  Height: (1 Byte);  // Height for this texture (Y2=Y1+HEIGHT)

// So each texture is a rectangular piece located at especified PAGE, in the cordinates (X1, Y1) - (X1+width, Y1+height).

//Next you have to load the raw texture data in 24 bits RGB pixel format, first you read the size in bytes for the whole raw data and then it come the raw texture data.

Note: I don;t have clear where is defined if a pixel is transparent, i guess that using the 24th bit, but i am not sure.

* Raw_data_size: (4 Bytes)
* Raw_Data:  (Raw_data_size bytes sizes).
// For find out the total textures pages (256x256 each) availible in the WAd::  Total_pages:=Raw_data_size / 196608.

//Next come the Mesh pointers table, this table is used as un mesh index  table for quick find where in the file begin the data for a especific mesh.

* Amount_pointers_records : (4 bytes)
* Pointer_records :  ( Amount_pointers_records*4  bytes)

//Each record is a 4 bytes value used as offset from the begining mesh section.  The movables and statics structures point to a index in this table, the reader then use the offset value stored in this entry and from the begining mesh section it skip offset bytes to find out where in the file begin the data for the Mesh pointed for the Movable or for the static structure.

//Is not clear why some entries in this table are unused, so you will found just the "0" value in severals entries, so Amount_pointers_records  WILL NOT GIVE YOU the amount meshes availibles in the wad.
In Originals WADs from CD counting the pointers_records different that "0"  will give you the amount meshes+1 availibles but i found in WADs built with TRWEST  duplicated mesh pointers entris even severals times, so is not safe to find the total mesh availibles using the mesh pointer table, better find out this using the info found in the mesh section.
 

//Next come the mesh section.

// All objects in a wad is built s using one or more individual pieces called meshes , each mesh  is a bunch of Polygons that will draw a object piece.
Normally all ornaments are just one mesh, and the movables (the objects that will have some animation) will use severals pieces, then each piece can be animated independientily at realtime for the engine, the wad store un bunch of cordinates offsets and angles values that will tell to the engine how to move and rotate at realtime each piece, so all objects are drawn for the user using a CAD program ONLY ONCE and at ONLY ONE position, later the engine will redraw in game for his self all animations using the bunch of offsets and angles values.

* Amount_mesh_data : (4 Bytes)

//will give you the amount bytes that was necessary to store the info for all the mesh availibles in the WAD. This value is interpreted as amount words ( word=2 bytes), so you have to multiply this value by 2 for get the total bytes that is currently needed for hold the whole mesh section.

//Next come each Mesh data record, at this point you don't know yet how much records you will found next.

//At this point is a good idea to save the current file position to a variable called begining_mesh_section, then you can use  in conbination with a mesh pointers data found in the mesh pointer table to locate a especific mesh, just do :

mesh_position:=begining_mesh_section+mesh_pointers[x]

"x" is a mesh pointer index referenced in the statics or movables records

//Before start reading each mesh record also is good idea to calc where is the file position where the mesh data will end:

Mesh_data_end:= begining_mesh_section+(amount_mesh_data*2) //mesh_data end will hold where finished the mesh section.

//Now read a mesh record in the fallow way:

// Mesh record
==========

* sphere_X : (2 bytes)
* sphere_Y : (2 bytes)
* sphere_Z : (2 bytes)
* spehere_radius: (4 bytes)

//These seem to be cordinates and the radius data for draw a invicible sphere used for colisional testing in the game. Only mesh pieces that are used for Movables will use these data, mesh used for ornaments (statics) will have "0" values.
// the x, y, z, cordinates realy point to the center of the mesh, but for me is not clear how the sphere_radius is interpreted, but i know that if you put "0" to the radius then this piece will be unsolid.
 

//next come the table vertices, this is a optomized table where is store all points (vertices) used for the polygons (faces)

* Amount_vertices: (2 bytes)  //amount vertex records to follow.
* Vertices            : (amount_vertices*6 bytes ) //all vertices records.

//Each record is 6 bytes long and it have to be readed as:

-  X   (2 bytes)  //x cordinate
-  Y   (2 bytes)  //y cordinate
-  Z   (2 bytes)  //z cordinate

//These values have to be interpreted as signed 16 bits from -32768..32767.
// These values are 1000/1 scaled, so the values will be so big for normals Directx, Opengl or CAD renders, so it's good
  idea to make smaller these values when you are going to use them. Just divide each value for 1000 or for 100

//Next come the Normal/Lights vertices tables, this table hold values that tell to the engine how the faces will be affected for externals lights. There are two ways for calc how the light is reflected in the faces: Using Normals values or using Lighting values. The meshes used for movables are using the "normal" method and the statics mesh are using the "lighting" method.

* Amount_records: (2 bytes)
//amount records to fallow, this field have to be interpreted as signed 16 bits, if this is a positive value then next come records with  "Normals" values, if negative then next come records with "lighting" values.

* Normals or Lighths values:
//If amount_records is positive then this is amount_records*6 bytes sizes, if  negative then it is abs(amount_records)*2 bytes size.

Normals records have to be interpreted as:
- normal_x : (2 bytes)
- normal_y: (2 Bytes)
- normal_z: (2 Bytes)

For Lighting records:

- Light : (2 Bytes)

// Currently i don;t have idea how to re-calc the "lighting" method used for the statics mesh.

//Next come each face definition that will draw this mesh.

* Amount_polys : (2 bytes)
//how much polys records come next for draw the mesh, there are two kind polys used, Reactangles and Triangles.

//Each poly record have to be readed in the follow way:

* Type_poly: (2 bytes) // If this is value "9" then the this is a rectangular face else it's triangular face.
* p1   (2 bytes)
* p2   (2 bytes)
* p3  (2 bytes)
* p4  (2 bytes) // Read this field only if type_poly = 9.
//Those are the points corners for the face, they are indexes to the Vertice table, this is a smart way to define the faces because duplicated vertex are stored just once in the vertice table, then the engine only have to do the calcs over the table vertice for rotate or move (anim) the meshes.

* Texture : (2 bytes) //texture index and texture flag to apply in this face.
* Attrib   :  (2 bytes) //atribute for the face, 0= normal, 1=semi-transparent, maybe 2=transparent but i am not sure.

................................................................................................................................................................................
The Texture field is a tricky one, and have to be interpreted well for apply corectly the texture map over the faces.
you have to interpret this as un 16 bits ( from 0..15 bits) and interpret the bits in the follow way:
 

When used in rectangular faces:

 Bits
------
- 0..11   =  Texture index, (pointing to the texture table), interpreted as signed value, if negative then the texture is "X" fliped.
- 12..15 =  These bits will be the same as the Bit 11.
 

When used in Triangular faces:

Bits
-----
- 0..10    =  Texture Index (pointing to the texture table) always a positive value.
- 11        =  Unused, always 0?
- 12..14  =  Triangle type, there are 4 different posibles triangles values: 0, 2, 4, 6.
- 15        =  Flip flag,  0=normal, 1 = X fliped.

.........................................................................................................................................................................

// Then it come the next poly record, it;s is necesary to count how much rectangles are you founding when you are reading the total polys records and store this count in a variable called total_rectangles.

When all polys for this mesh are done you sometimes will need to read a padded 2 bytes, before start reading the next mesh record, if the total rectangles used for draw this mesh is a odd value (  (total_rectangles mod 0)<>0  ) then you will found the 2 padded bytes else just start reading the next mesh record.

This 2 padded bytes has not any usefull meaning, but if  you are going to build WADs files  please include this rule.

* Padd_bytes: (2 bytes),  read this field only if total rectangles is a odd number.

//After reading a complete mesh record you have to compare the current file position with the mesh_data_end variable if the current file position is equal or higher then there is no more mesh records to read, otherwhise read the next mesh record.

Also keep count how much Meshes records are you reading because is the only way to know how much mesh are availibles at the end in the WAD.

//After the Mesh section it come more sections that i am not going to enter in detail yet because i have not working with them directly, but a more detailid explanation about these section can be found at the roseta stone document.

 //anims
* Num_anims:  (4 bytes)
* Anim_Data  : (num_anims* 40 bytes size)
// The anims structure define what animations each movable has,  for example wallking, running, attacking, dying etc.
It's hardcoded in the engine how much animation a especific movable has, each movable is marked with a Object ID, the engine espect a fixed amount of animation based in tghe object ID, also each # animation already have a especific meaning for the engine for each Object ID.

for example, if a object ID is hardcoded to expect this animation order:

Anim #         Meaning
----------------------------
- 1           Stay
- 2          Start walking
- 3          walking
- 4          stop walking
- 5          start runing
- 6          Running
- 7         Attack.
- 8         Die
 

When you import a movable from another TR game version over thise slot, then new movable could have more animations and in a different order, for this slot the engine will use ONLY the first 8 anims no matter how much anims you imported over this slot, also the engine will still using the anim# 2 for start walking, #3 for walking... etc. so you have to fix correctly the anims in your new movable in the same order that the slot that you are using. There is not way to tell to the engine to use more #anims in the slot.

//States
* Num_states:  (4 bytes)
* states_data  : (num_states* 6 bytes size)

//anim dispatch
* Num_dispatch:  (4 bytes)
* dispacth_data  : (num_dispatch* 8 bytes size)
// These are a auxiliar data that tell to the engine how to change between anims. for example from change from the stay anims to
the start-walking anim and then to the wallking anim intead to change from stay to walk directly.

//anim commands
* Num_commands:  (4 bytes)
* commands_data  : (num_commands* 2 bytes size)
//this is a serie Opcodes (commands) that will be execute for the engine  when a especific #anim is played, like play the running steps sounds when the #running animation is played.

 //meshtree
* Num_meshtreedata::  (4 bytes)
* meshtree_data  : (num_meshtreedata* 4 bytes size)
// Here you will found how each mesh piece will be joined togeter for build a complete movable, in this structure you will found a mesh value that is a index to the mesh pointer table, then using the mesh pointer table you found the actual mesh.

//frames
* Num_framesdata::  (4 bytes)
* frames_data  : (num_framesdata* 2 bytes size)
//These are a bounch of offsets and angles values that will be aplied to the meshtree for re-draw at realtime each frame animation.

//movables
* Num_movables::  (4 bytes)
* movables_data  : (num_movables* 18 bytes size)
// Here you will found how much animated objects are availibles in the wad, here you will found the Item ID for each movable.
// Each record in this structure is a complete movable and point to the meshtree strutcture for tell to the engine how to draw this object.

This method of drawing the movable indirectly using the meshtree structure is very smart because this way each mesh piece can be re-used in the drawing of  another movable, a Torso mesh for example can be used in two different movables.
So be warned that editing a mesh can affect more that one object.

Also that is related to the problem of  dependency objetcs where somtimes you are obligated to export a object for be able to use sucessful a desired object. The solution will be to draw a separated mesh and fix the meshtreee structure for un-link some dependencies.

//statics mesh
* Num_statics:  (4 bytes)
* static_data  : (num_statics* 32 bytes size)
//this is the structure how much statics mesh (ornaments) are availibles in the wad. each record is 32 bytes long and have to be read in the follow way:

 - object_id   :   (4 bytes)   statics object ID matched in the Items table when the level is built.
 -  mesh         :    (2 bytes)   index to the mesh pointer table.

 -  vx1,vx2,vy1 : ( 2 bytes each) These are cordinates values interpeted as signed 16 bits and are used for draw a invisible
 -  vy2,vz1,vz2 : (2 bytes each)  bounding box used for visivility and colisional test when the game is runing.
 -  cx1,cx2,cy1 : (2 bytes each);
 -  cy2,cz1,cz2 : (2 bytes each);

 -  flag             :  (2 bytes) // flag, normalmente 1 o 2, desconosco el uso de este flag.
 
 
 
 

*********************  END OF DOCUMENT *********************************************
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Hosted by www.Geocities.ws

1