This document is a work in progress! TODO:
- Rename Section 1 and Section 2 based on block content purpose
Level Format[]
The overall level format for Driver 2 is identical to the first Driver for PSX. PSX levels consists of four different sections of data. These sections are described by the Section Definitions block, which must be the first data in the file. Blocks are simply containers for data that consist of a block identifier followed by a block size, which is then followed by that amount of data. The format of the data depends on the block identifier. The four sections are as follows:
- Section 1 Blocks - This section consists of the Section 1 Container block, which is a container for a list of blocks.
- Compressed Textures - This section consists of a series of compressed textures.
- Section 2 Blocks - This section consists of the Section 2 Container block, which is a container for a list of blocks.
- Sector Data - This section stores data such as textures, models, and world information for various sectors of the world. In order to read this section, you must use information from the Sector Info block.
Offset | Type | Size | Name | Description |
---|---|---|---|---|
0x0000 | uint32 | 4 | blockType | Identifier specifying the format/purpose of data. |
0x0004 | uint32 | 4 | blockSize | Size in bytes of block data. |
0x0008 | N/A | blockSize | data | Data for this block. |
Offset | Type | Size | Name | Description |
---|---|---|---|---|
0x0000 | Block | 2048 | sectionDefinitions | Must be of the Section Definitions block type. |
0x0800 | Block | Varies | section1Container | Must be of the Section 1 container block type. |
Varies | CompressedTexture[] | Varies | compressedTextureData | Compressed Textures. To read these, you must have information from the Texture Info block. |
Varies | Block | Varies | section2Container | Must be of the Section 2 container block type. |
Varies | N/A | Varies | sectorData | Data for sectors. To read this you must have information from the Sector Info block. |
Block Specifications[]
The following is a list of block identifiers and their corresponding format. Note that the vast majority of these identifiers are not used.
THIS SECTION IS A WIP[]
Block Identifier |
Corresponding Block Format |
Original name |
---|---|---|
1 (0x01) | Models | LUMP_MODELS |
2 (0x02) | World info | LUMP_MAP |
5 (0x05) | LUMP_TEXTURENAMES | |
7 (0x07) | Road map (unused) | LUMP_ROADMAP |
8 (0x08) | Roads (unused) | LUMP_ROADS |
9 (0x09) | Junctions (unused) | LUMP_JUNCTIONS |
10 (0x0a) | Road surfaces (unused) | LUMP_ROADSURF |
12 (0x0c) | LUMP_MODELNAMES | |
16 (0x10) | Road bounds (unused) | LUMP_ROADBOUNDS |
17 (0x11) | Junction bounds (unused) | LUMP_JUNCBOUNDS |
20 (0x14) | LUMP_SUBDIVISION | |
21 (0x15) | Low detail table for models | LUMP_LOWDETAILTABLE |
22 (0x16) | Motion Capture | LUMP_MOTIONCAPTURE |
24 (0x18) | Overlay Map | LUMP_OVERLAYMAP |
25 (0x19) | LUMP_PALLET | |
26 (0x1a) | LUMP_SPOOLINFO | |
28 (0x1c) | LUMP_CAR_MODELS | |
33 (0x21) | LUMP_CHAIR | |
34 (0x22) | LUMP_TEXTUREINFO | |
35 (0x23) | Section 1 Container | |
36 (0x24) | Section 2 Container | |
37 (0x25) | Section Definitions | |
40 (0x28) | Straights of Driver 2 | LUMP_STRAIGHTS2 |
41 (0x29) | Curves of Driver 2 | LUMP_CURVES2 |
42 (0x2a) | Junctions of Driver 2 | LUMP_JUNCTIONS2 |
43 (0x2b) | Unknown lump | |
255 (0xff) |
Section Definitions[]
Block Identifier: 37 (0x25) |
This block provides information on what offset and what size the four sections of the file are. Because of this, it must be found at the beginning of the level. The block simply consists of an offset and size for each section, followed by padding. The padding must align the block to a 2048 byte boundary, with the block identifier and size included. The padding is usually filled with 'DES!', but does not have to be. Offsets are realative to the start of the level file.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 |
section1Offset |
Offset to section 1 block list. |
0x0004 | uint32 | 4 | section1Size | Size of section 1 block list. |
0x0008 | uint32 | 4 | compressedTexturesOffset | Offset to compressed texture data. |
0x000C | uint32 | 4 | compressedTexturesSize | Size of compressed texture data. |
0x0010 | uint32 | 4 | section2Offset | Offset to section 2 block list. |
0x0014 | uint32 | 4 | section2Size | Size of section 2 block list. |
0x0018 | uint32 | 4 | sectorDataOffset | Offset to sector data. |
0x001C | uint32 | 4 | sectorDataSize | Size of sector data. |
0x0020 | N/A | 2008 | padding | Padding to 2048 byte align this block (including block type and size). |
Section 1 Container[]
Block Identifier: 35 (0x23) |
This block type makes up one of the four sections of the file. It is simply a container for a list of block structures. The section data that this block resides in must be padded to a 2048 byte boundary, but the actual size of this block does not have to be. Unlike the original Driver's level format, this container does not have a block count. Instead, block are read sequentially until a block type with identifier 255 (0xff) and size 0 is encountered, which signals the end of the block list. The blocks are dword padded (i.e. to nearest 4-byte boundary), and the padding is not accounted for in the contained block sizes.
TODO: Insert what blocks are found in this container.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
Block[] |
Varies |
blocks |
List of blocks containing data for level. Blocks are read until a block with 0xff as identifier is encountered. |
Section 2 Container[]
Block Identifier: 36 (0x24) |
This block type is exactly the same as the Section 1 Container, except for the identifier and the types of blocks that are typically contained.
TODO: Insert what blocks are found in this container.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
Block[] |
Varies |
blocks |
List of blocks containing data for level. Blocks are read until a block with 0xff as identifier is encountered. |
World Info[]
Block Identifier: 2 (0x02)
Original name: LUMP_MAP |
This block type describes world dimensions, and contains bridged model defs.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 | uint32 | 4 | width | Map width |
0x0004 | int32 | 4 | height | Map height |
0x0008 | int32 | 4 | tileSize | Leftover from Driver 1 |
0x000C | int32 | 4 | numSectors | Sector count |
0x0010 | int32 | 4 | visTableWidth | Cell table width |
0x0014 | int32 | 4 | numAllPackedModelDefs | Number of all packed cells in level including bridged cells |
0x0018 | int32 | 4 | ambientColor | Leftover from Driver 1 |
0x001C | int32[] | 4*3 | sunAngleXYZ | Leftover from Driver 1. Sun angle? |
0x0028 | int32 | 4 | numBridgedObjects | Bridged model defs count |
0x002C | PackedModelDef | numBridgedObjects | packedModelDefs | Packed Model defs that placed between sectors (Look at Sector Info) |
Texture Names[]
Block Identifier: 5 (0x05)
Original name: LUMP_TEXTURENAMES |
This block contains a list of texture names for the level. These texture names are referenced by the Texture Info block.
The actual data for this block consists of an array of characters the length of the block size. Names are stored as null-terminated strings one after another. There should generally not be any empty strings, but this is not guarenteed. There may be additional null characters at the end of the array to dword align the block.
Offset | Type | Size | Description |
---|---|---|---|
0x0000 | char[] | blockSize |
Series of null terminated strings for texture names. |
Model Names[]
Block Identifier: 12 (0x0c)
Original name: LUMP_MODELNAMES |
This block contains a list of model names for the level. The game uses some model names to find models such as cones, barrels, etc. Not all models are named, and not all named models are searched for in the game.
The actual data for this block consists of an array of characters the length of the block size. Names are stored as null-terminated strings one after another. Empty strings (i.e. just the null character) are allowed and must be accounted for when traversing the array. There may be additional null characters at the end of the array to dword align the block, so the number of models should be gained from the model block and not counting how many nulls occur in the Model Names block. There is guarenteed to be at least as many null-terminated strings as models in the level.
Offset | Type | Size | Description |
---|---|---|---|
0x0000 | char[] | blockSize |
Series of null terminated strings for model names. |
Car Models[]
Block Identifier: 28 (0x1c)
Original name: LUMP_CAR_MODELS |
The car models block contains the models for the cars in the level. It has identical format to the regular models block, except in that it adds an offset table to the models. Each offset entry contains an optional offset to the clean, damaged, and low detail models for that car. There is always 13 entries, so there is a maximum of 13 cars per level. All offsets are relative to the position immediately following the list of offset entries.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | cleanOffset | Offset to the clean model data for this car, or 0xffffffff if no model. |
0x0004 | uint32 | 4 | damagedOffset | Offset to the damaged model data for this car, or 0xffffffff if no model. |
0x0008 | uint32 | 4 | lowOffset | Offset to the low detail model data for this car, or 0xffffffff if no model. |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | size | Size of the following model data. |
0x0004 | Model | size | model | Model data. |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
int32 |
4 | numModels | Total number of models found in this block. |
0x0004 | CarModelOffsets[] | 13* | offsets | Offsets to the models in the block. |
0x00a0 | int32 | 4 | unk | Always -1? |
0x00a4 | ModelSizePair | numModels* | models | Models for the level. Not sure if dword aligned or not. |
Car Palettes[]
Block Identifier: 25 (0x19)
Original name: LUMP_PALLET |
This block holds palettes for the various colors of vehicles. The block consists of a total unique palette count followed by a list of car palette entry structures.
Car palette entries consist of the car number which is being described (or it might be the paint job being described?), the atlas index which the palette belongs to, and the texture index which the atlassed sub-texture comes from. It then has a palette index, which if equal to 0xffffffff, is followed by a PSX 16-color palette structure, otherwise if not equal to 0xffffffff it is equal to the index into the unique palette array and no further data occurs in the entry.
Entries are to be read in by first reading the carNum member. If it is equal to 0xffffffff, it signals the end of the list and the rest of the structure should not be read. Otherwise the atlasIndex, texIndex, and paletteIndex members can be read in, and if paletteIndex equals 0xffffffff, a palette structure is read in. This is repeated until the terminating 0xffffffff is found.
The unique palette count gives the total number of palettes that will occur in the block. As palettes are found in the palette entry structures, this is filled in. To do this one must keep track of the current index, and increment it after each new palette is found.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
int32 |
4 | carNum | Number of the car which this corresponds to? Maybe paint job index? If equal to 0xffffffff, it signals the end of the list of entries. |
0x0004 | int32 | 4 | atlasIndex | Index of the atlassed sub-texture which this palette is for. |
0x0008 | int32 | 4 | texIndex | Index of the texture the atlassed sub-texture comes from. |
0x000C | int32 | 4 | paletteIndex | If equals 0xffffffff, a palette follows this member. Otherwise it is an index into the unique palette list for this block. |
0x0010 | Palette | 32 | palette | Only follows paletteIndex if paletteIndex is 0xffffffff. Standard PSX 16-color palette. |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | numPalettes | Total unique palettes in this block. This is not the same as the number of entries in the block. |
0x0004 | CarPaletteEntry[] | Varies | entries | Entries for the block. See above for termination condition. |
Texture Info[]
Block Identifier: 34 (0x22)
Original name: LUMP_TEXTUREINFO |
The texture info block contains information about the textures and texture atlasing in the level.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint16 |
2 | flags | Only interested in 1 and 4 for moment, which indicate compressed. |
0x0002 | uint16 | 2 | carnum | Might not be carnum anymore |
0x0004 | uint32 | 4 | offset | Holdover from old level format and is not used (I think). At least does not tell where textures are located. |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint16 |
2 | importIndex | The index which it was imported in as in the devs program? Not needed. |
0x0002 | uint16 | 2 | nameOffset | Offset of string into the texture names data for this atlas. |
0x0004 | uint8 | 1 | x | x position. |
0x0005 | uint8 | 1 | y | y position. |
0x0006 | uint8 | 1 | w | width. 0==256? |
0x0007 | uint8 | 1 | h | height. 0==256? |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | index | Index of this texture. |
0x0004 | uint32 | 4 | size | Size of compressed texture. |
Although compressed texture sizes structs have 16 nodes, only the first numTextures ones are used. Textures can then be read in sequentially.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | numTextures | Number of textures in list. |
0x0004 | CompressedTextureSize[] | 16*8 | textureSizes | Indicies and sizes of compressed textures. |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 | numTextures |
The number of 256x256 textures in the level. |
0x0004 | uint32 | 4 | numAtlasDefinitions | The number of atlas definitions in this block. |
0x0008 | TextureFlags | numTextures* | textureFlags | Flags for the textures. |
Varies | uint32 | 4 | unk1 | Possibly more flags |
Varies | uint32 | 4 | unk2 | Possibly offset to another texture? |
Varies | TextureAtlasInfo | numTextures* | textureAtlasInfos |
Describes position and size of atlased textures. |
Varies | CompTexSizes | Varies? | flag1TexSizes | Contains sizes for textures with flag 1 set. |
Varies | CompTexSizes | Varies? | flag4TexSizes | Contains sizes for textures with flag 4 set. |
To read in compressed textures, seek to start of compressed textures section. Read in all flag 1 textures first, then read in all flag 4 textures. Other textures can be found in section 4 (sector data) which needs Sector Info block to read. Most textures will not have any texture data associated with them, probably because they were stripped from the level due to not being used.
Sector Info[]
Block Identifier: 26 (0x1a)
Original name: LUMP_SPOOLINFO |
The sector info block contains information needed for traversing and reading data from section four (the sector data section) of the level.
Note that all offsets and sizes are to be multiplied by 2048 to get actual offset and size. Offsets are relative to start of sector data section (section 4 of level).
Shared data groups contain information about textures and models that are loaded depending on your position in the level. These structures are indexed from the Sector Data Info struct. Note that most of these have values which are not offsets/sizes (I don't know what these ones are for yet) so only attempt to use the ones that are referenced from a Sector Data Info structure. Textures are stored in a list with the usual uncompressed format (i.e. number of palettes followed by palette data, padding, then uncompressed texture).
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint16 |
2 |
textureOffset | Offset to textures. Textures are in uncompressed format. |
0x0002 |
uint16 |
2 |
modelsOffset | Offset to models. |
0x0004 |
uint16 |
2 |
unk1 | |
0x0006 |
uint16 |
2 |
unk2 | |
0x0008 |
uint8 |
1 |
modelsSize | Number of 2048 chunks of model data. |
0x0009 | uint8 | 1 | unk3 | |
0x000a |
uint8 |
1 |
numTextures | Number of uncompressed textures at offset. |
0x000b | uint8 | 1 | unk4 | |
0x000c |
uint16 |
2 |
unk5 | |
0x00e |
uint16 | 2 | unk6 |
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint8[] | 16 | textureIndices | Indices of textures that are present in this group. Unused indices are filled with 0xff. |
Note: There are not offsets to individual sections of data within a sectors data info. Instead you must seek using the sizes listed below. The segments appear in the following order (for known used segments): contentsTableSize, contentsNodesSize, modelDefsSize, roadTableSize.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 | uint16 | 2 | x | X offset relatively of sector |
0x0002 | int16 | 2 | y_addindex | packed "+1024 to model index" (1 bit) and Y offset (15 bits) |
0x0004 | uint16 | 2 | z | Z offset relatively of sector |
0x0006 | uint16 | 2 | rotation_model | packed rotation (6 bit) and model index (10 bit) |
To unpack rotation:
rotation = (rotation_model & 0x3f) / 64.0f*PI_F*2.0f;
To unpack model index:
modelindex = (rotation_model >> 6) + ((object.y_addindex & 0x1) ? 1024 : 0);
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint16 |
2 |
sectorOffset | Offset to the start of the sector data. |
0x0002 |
uint8 |
1 |
unk0 | |
0x0003 |
uint8 |
1 |
unk1 | |
0x0004 |
uint8 |
1 |
visibilityOffset | Always 0 |
0x0005 |
uint8 |
1 |
contentsOffset | Holdover from Driver 1 |
0x0006 |
uint8 |
1 |
packedCellsOffset | Cells offset relatively contentsOffset |
0x0007 |
uint8 |
1 |
modelDefsSize | Number of 2048 byte chunks of packed model def structures. |
0x0008 |
uint8 |
1 |
dataGroupIndex | Index into the array of shared data groups, or 0xff if no data group is used. 0xFF if no datagroup used |
0x0009 | uint8 | 1 | unk2 | |
0x000a | uint8 | 1 | roadTableSize | Holdover from Driver 1, not sure what this is in Driver 2 yet. |
0x000b | uint8 | 1 | heightmapSize | Holdover from Driver 1, not sure what this is in Driver 2 yet. |
To access Packed Model Defs you need to use sectorDataOffset from Section Definitions, all offsets aligned by 2048 bytes. So, for each sector packed cells are located at sectorDataOffset + 2048 * (sectorOffset + contentsOffset + packedCellsOffset). Read them sequentally until you hit DES! padding.
Offset |
Type |
Size |
Name |
Description |
---|---|---|---|---|
0x0000 |
uint32 |
4 |
unk |
Unknown |
0x0004 |
uint32 |
4 |
unkSize | Unknown size. |
0x0008 |
N/A |
unkSize |
unkData |
Always 0? |
Varies? |
uint32 |
4 |
numDataGroups |
Number of shared data group infos. |
Varies? |
SharedDataGroup[] |
numDataGroups* |
dataGroupInfos |
Information about shared data group position/size. |
Varies? |
DataGroupTextures[] | numDataGroups* | dataGroupTexs | Texture indicies of textures included in the data group. |
Varies? |
uint32[] |
4*12 |
unk2 | Unknown data. 12 ints? |
Varies | uint32 | 4 | numSectors | Number of sectors in level. |
Varies | uint16[] | numSectors* | sectorDataOffsets | Gives offset in sectorDataInfos if sector has data, otherwise is 0xFFFF |
Varies | uint32 | 4 | dataInfoSize | Size of following sector-data-info data. |
Varies | SectorDataInfo | (dataInfoSize/12)* | sectorDataInfos | Info on offsets and sizes of sector data segments. |
In proper way sectorDataInfos accessed by using sectorDataOffsets. To pick valid sector data offset you'll need a sectorsW and sectorsH.
To find width and height of two dimensional sector array:
sectorsW = width / visTableWidth; sectorsH = height / visTableWidth;
Traverse sectorDataOffsets as two-dimensional array:
for(y = 0; y < sectorsH; y++) { for(x = 0; x < sectorsW; x++) { sectorIndex = y*sectorsW + x; ... } }
Accessing SectorDataInfo:
sectorOffset = sectorDataOffsets[sectorIndex]; if(sectorOffset == 0xFFFF) continue; // skip, it's empty sectorDataInfo = sectorDataInfos[sectorOffset/12];
To find sector X and Z position, you need to multiply X or Y by 65536