The structure of Carmageddon 2 game files ----------------------------------------- by Dan L'Ecuyer This document covers the following file types used in C2: ACT - actor file DAT - model file MAT - material file PIX - image file TWT - library file With the exception of TWT, the file structures are all based on a common record layout. A record is composed of a 4-byte type word and a 4-byte length word followed by any amount of data. For example, here is the first record for each type of file: ACT - 00.00.00.12 00.00.00.08 00.00.00.01 00.00.00.02 DAT - 00.00.00.12 00.00.00.08 00.00.FA.CE 00.00.00.02 MAT - 00.00.00.12 00.00.00.08 00.00.00.05 00.00.00.02 PIX - 00.00.00.12 00.00.00.08 00.00.00.02 00.00.00.02 The important thing to note about these structures is that they use a big-endian byte order. An Intel-based PC uses a little-endian byte order. That is, the CPU memory is organized as lowest byte first. A big-endian processor such as the 68000 series formerly used on the Apple Mac organizes memory as lowest byte last (this is big-endian order). My guess is that the file structures used in C2 do not originate on the PC. Perhaps the original development environment used to create Carmageddon (starting from version 1) was a more advanced machine with a big-endian processor. In the above structures, I used a combination of network address syntax and hexadecimal number representation. Each 4-byte number is separated into four bytes using a decimal point. Each single-byte value is expressed as hexadecimal. In decimal, the above would look like: ACT - 0.0.0.18 0.0.0.8 0.0.0.1 0.0.0.2 DAT - 0.0.0.18 0.0.0.8 0.0.250.206 0.0.0.2 MAT - 0.0.0.18 0.0.0.8 0.0.0.5 0.0.0.2 PIX - 0.0.0.18 0.0.0.8 0.0.0.2 0.0.0.2 In any case, the initial record is similar for each file type. The type word is always the value 12h or 18d. The length word is 8 (since 8 bytes of data follow). The third word indicates the file type. The last value is always 2 for both C1 and C2. I have been able to identify the following record types used in the various files (shown in the usual order of occurrence): ACT - 23h, 35d = actor name and attributes ACT - 2Bh, 43d = transformation matrix ACT - 25h, 37d = unknown (contains no data) ACT - 32h, 50d = bounding box ACT - 29h, 41d = start of hierarchy level ACT - 26h, 38d = material names ACT - 24h, 36d = model name ACT - 2Ah, 42d = end of hierarchy level DAT - 36h, 54d = model name and attributes DAT - 17h, 23d = vertices DAT - 18h, 24d = texture coordinates DAT - 35h, 53d = faces DAT - 16h, 22d = material names DAT - 1Ah, 26d = face materials MAT - 3Ch, 60d = material name and attributes MAT - 1Ch, 28d = image name PIX - 3Dh, 61d = image name and attributes PIX - 21h, 33d = pixel data With only a few small differences, the above applies to the C1 file formats as well. Note that the P08 and P16 files are simply PIX files which contain more than one pix. Warning: Plaything does not always write the records with the correct length attribute. The game and Plaything both ignore the lengths when loading the data files. That's fine for the game but it doesn't help if you want to write a file scanning utility. Floating point representation ============================= Many values in the game files are floating point rather than integer. Expressed in hexadecimal, a floating point number makes no sense. For example, the number 1.0 is 3F.80.00.00 in hexadecimal. The floating point bits break down like this: bit 31 = sign bit (1 is negative, 0 is positive) bits 30 to 23 = exponent (-127 to +127) bits 22 to 0 = mantissa In big-endian format, the sign bit is the highest bit in the first byte while the exponent is in the lower 7 bits of the first byte and the highest bit of the second byte. ACT file construction ===================== Beginning of the file: 00.00.00.12 00.00.00.08 00.00.00.01 00.00.00.02 ACT - 23h, 35d = actor name and attributes 2 bytes = attributes (meaning unknown) X bytes = actor name 1 byte = null ACT - 2Bh, 43d = transformation matrix Always 48 bytes in an array of 12 floating point values. Default values are indicated in brackets. Xx (1) Yx (0) Zx (0) Xy (0) Yy (1) Zy (0) Xz (0) Yz (0) Zz (1) Px (0) Py (0) Pz (0) Px, Py and Pz are absolute coordinates for the position of the actor in 3D space. It is beyond the scope of this document to explain the function of the transformation matrix. ACT - 25h, 37d = unknown (contains no data) This is always present in ACT files generated by Plaything. I have not experimented to see what effect this has on the game engine if this record is omitted. I just assume that it is needed. ACT - 32h, 50d = bounding box Always 24 bytes in an array of 6 floating point values. Xmin Ymin Zmin Xmax Ymax Zmax ACT - 29h, 41d = start of hierarchy level Empty record indicating the start of a new sublevel in the hierarchy. ACT - 26h, 38d = material names This is not normally used. Models typically contain their own list of materials. However, it can be sometimes advantageous to list the materials in the actor file instead of the model file. I have not experimented with this. ACT - 24h, 36d = model name X bytes = model name 1 byte = null ACT - 2Ah, 42d = end of hierarchy level Empty record indicating the end of a sublevel in the hierarchy. The number of end markers must match the number of start markers. Also, each actor must have its own end marker. Note: There MUST be a null marker (8 null bytes) at the end of an ACT file else the game will crash. The ACT file for a track has a special actor name at the beginning. The format of the name is (with a single space character between each part): PP01 X Z B N X = number of track models in the X direction Z = number of track models in the Z direction B = extra buffer space (for what?) N = number of noncars (can be zero) DAT file construction ===================== Beginning of the file: 00.00.00.12 00.00.00.08 00.00.FA.CE 00.00.00.02 DAT - 36h, 54d = model name and attributes 2 bytes = attributes (meaning unknown) X bytes = model name 1 byte = null DAT - 17h, 23d = vertices 4 bytes = number of vertices X bytes = 3 floating point values for each vertex DAT - 18h, 24d = texture coordinates 4 bytes = number of coordinates X bytes = 2 floating point values for each coordinate DAT - 35h, 53d = faces 4 bytes = number of faces X bytes = 9 bytes for each face Each face: 2 bytes = 1st vertex 2 bytes = 2nd vertex 2 bytes = 3rd vertex 3 bytes = unknown (Plaything uses 0.1.0) The vertices are numbered from 0 on upward. Due to the fact that a 16-bit value is used to identify each vertex, it is impossible to have more than 65,536 vertices in a single model. If the index is considered to be a signed number (I don't know if the game does that), then the maximum number of vertices is 32,768. DAT - 16h, 22d = material names 4 bytes = number of material names X bytes = name plus null byte for each material DAT - 1Ah, 26d = face materials 4 bytes = number of faces 4 bytes = unknown (00.00.00.02) X bytes = 2-byte index for each face The index is 1-based and refers to the preceding list of materials. Note: Each model in a DAT file MUST end with a null marker (8 null bytes). There does not appear to be any support for smoothing groups within the data structure. It is possible that the unknown 3 bytes for each face may have something to do with smoothing groups. Experimentation has shown that it is possible to funk up collision detection by playing with these bytes. That probably means that they do not have anything to do with smoothing. I still need to determine whether they have some effect on lighting. MAT file construction ===================== Beginning of the file: 00.00.00.12 00.00.00.08 00.00.00.05 00.00.00.02 MAT - 3Ch, 60d = material name and attributes 4 bytes = colour RGBf (FF.FF.FF.FF) 4 bytes = *ambient lighting (3D.CC.CC.CD) 4 bytes = *directional lighting (3F.33.33.33) 4 bytes = *specular lighting (00.00.00.00) 4 bytes = *specular power (41.A0.00.00) 4 bytes = flags (00.00.00.21) 24 bytes = transformation matrix 4 bytes = *unknown (0A.1F.00.00) 13 bytes = *null X bytes = material name 1 byte = null Default values (generated by Plaything) are shown in brackets. Attributes prefixed with an asterisk do not have any visible effect in the game. The flag byte in the colour attribute may be either FFh or not FFh. If not FFh then faces using that material disappear from the game (any possible use?). The transformation matrix is 2D and follows the same format as the 3D matrix but with one less dimension. It does work. I currently only use it to flip the axes on a material but you can do fancier things than that. The flag bits are as follows: 00.00.00.01 - lit 00.00.00.02 - pre-lit 00.00.00.04 - smooth 00.00.00.18 - env mapped 00.00.00.20 - *correct perspective 00.00.00.40 - decal 00.00.07.80 - i/u/v 00.00.08.00 - always visible 00.00.10.00 - *two-sided 00.00.20.00 - force front 00.00.40.00 - dither 00.00.80.00 - nil 00.07.00.00 - map/mip 00.08.00.00 - fog local 00.10.00.00 - subdivide 00.20.00.00 - Z transparency 00.40.00.00 - nil 00.80.00.00 - nil The names are taken from the Plaything descriptions for these flags. Some of them don't do anything and some do weird stuff. Only two flags, which I have indicated with an asterisk, seem useful. The "correct perspective" flag does nothing in-game but it works in Plaything. The "two-sided" flag is, of course, pretty useful since it makes materials like fences and windows visible from both sides. MAT - 1Ch, 28d = image name X bytes = image name 1 byte = null Note: Each material in a MAT file must end with a null marker. PIX file construction ===================== Beginning of the file: 00.00.00.12 00.00.00.08 00.00.00.02 00.00.00.02 PIX - 3Dh, 61d = image name and attributes 1 byte = image type 2 bytes = unknown (equals image width) 2 bytes = image width 2 bytes = image height 6 bytes = unknown (null) X bytes = image name 1 byte = null The image type may be 03 for an 8-bit image, 05 for a 16-bit normal image or 12h (18d) for a 16-bit translucent image. An 8-bit image can only support transparency. PIX - 21h, 33d = pixel data 4 bytes = number of pixels 4 bytes = bytes per pixel (1 for 8-bit, 2 for 16-bit) X bytes = pixel data Note: Each image in a PIX file must end with a null marker. For 8-bit images, the pixel data is one byte per pixel. This byte indexes the colour palette (null represents transparency). For 16-bit images, the pixel data is two bytes per pixel. There are two colour formats. This is the normal format: bits 15 to 11 = red (5 bits) bits 10 to 5 = green (6 bits) bits 4 to 0 = blue (5 bits) This is the translucent format (four bits per channel): bits 15 to 12 = translucency (0 = transparent, 15 = opaque) bits 11 to 8 = red bits 7 to 4 = green bits 3 to 0 = blue TWT file construction ===================== 4 bytes = size of TWT file 4 bytes = number of files X bytes = 56-byte header for each file The header is: 4 bytes = file size X bytes = file name 1 byte = null Y bytes = padding to make 56 bytes Each file follows in the same order as the headers. Important note: the files MUST be padded to a multiple of 4 bytes. For example, a 16-byte file does not need padding. A 15-byte file needs one byte of padding (at the end of the file). Failure to pad the files with the correct number of bytes will crash the game.