**The unofficial 3DO Need for Speed files format specifications by Versus (vas.1987), 2021 (version 0.9)**. Based on\\ \\ THE UNOFFICIAL NEED FOR SPEED FILE FORMAT SPECIFICATIONS - Version 0.2\\ Copyright © 1995-96, Denis AUROUX (MXK) - auroux@clipper.ens.fr And OpenNFS1 project by Jeff Harris. [[https://github.com/jeff-1amstudios/OpenNFS1|https://github.com/jeff-1amstudios/OpenNFS1]]\\ _ Note that all data is BIG ENDIAN. **A) CAR FILES** \\ Car files are located at: DriveData\CarData. *.WrapFam – car’s exterior view: 3D model + textures\\ *.bigdashfam – car’s interior view\\ *.bigSpecsFam – car’s specs\\ *.digitalfam – speedometer digits\\ *.dashFam – not used?\\ *.dashConstants – not used?\\ *.TDDyn - not used?\\ *.TireR – not used?\\ *.TireF - not used?\\ *.spec - not used?\\ *.carSlideArt - not used? All files with *.WrapFam extension are cars 3D exterior model with textures. Each file represents a single car. These files are 'wwww' files containing four chunks. The file structure is the following: first a 24-byte header, then four\\ chunks. The header format is the following: ^offset^length^data| |00|4|'wwww'| |0x04|4|4 (number of chunks)| |0x08|4|0x18 (offset of the first chunk)| |0x0C|4|offset of the second chunk| |0x10|4|offset of the third chunk| |0x14|4|offset of the fourth chunk| **The first, second and the third chunks** correspond to different LODs of the car (from Lowres to Highres), each one consists of two subchunks. These subchunks are ORI3 (describe how the car is to be drawn (position and orientation of each car element) and SHPM (provide the bitmaps referenced by the ORI3 chunks). Note that the offsets specified in the bitmap directories are relative to the 'SHPM' header. \\ **The fourth chunk** has the size 0x1DC. It somehow affects car dynamics during crashes or some other situations. If all these chunk bytes are set to 0, car starts spinning with increased speed after the crash. I tested it also on a traffic car. Sometimes it moves to the opposite direction, sometimes just not moving. Charts below shows values representation within the most of the chunk data except chunk’s header. [[https://3dodev.com/_detail/documentation/file_formats/images_for_nfs_files_format/555.png?id=documentation:file_formats:nfs|{{https://3dodev.com/_media/documentation/file_formats/images_for_nfs_files_format/555.png?nolink&495x310}}]] [[https://3dodev.com/_detail/documentation/file_formats/images_for_nfs_files_format/445.png?id=documentation:file_formats:nfs|{{https://3dodev.com/_media/documentation/file_formats/images_for_nfs_files_format/445.png?nolink&494x306}}]] Each chunk except 4th have ‘wwww’ header with 2 subchunks: ‘ORI3’ and ‘SHPM’. ’ORI3’ chunk is for 3D object geometry, ‘SHPM’ chunk is for object’s textures. **B)** \\ A 3DO 'ORI3' chunk consists of a header followed by six blocks. Block numbering refers from PC-files version (see PC NFS file format specifications mentioned above). If block number is present in PC version, it has the same purpose is in 3DO version. Block numbers which doesn’t exists in PC version have unique 3DO format. Blocks numbering doesn’t matter anything. \\ The header has length 120 (0x78) bytes and the following structure: ^offset^length^data| |00|4|'ORI3'| |0x04|4|chunk length in bytes| |0x08|4|0x1F4| |0x0C|4|0| |0x10|4|size of block 8 in 12-byte records| |0x14|4|offset of block 8 = 0x78| |0x18|4|0| |0x1C|4|0x280 All player cars have 0x280 value, traffic cars may have different values or 0x280. Doesn’t affect any performance (?)| |0x20|4|size of block 10 in 24-byte records| |0x24|4|offset of block 10| |0x28|8|identifier string| |0x30|4|Equals value on 0x20 offset (block 10 size)| |0x34|4|0| |0x38|4|0| |0x3C|4|offset to blank 8 bytes (0). Equals to offset 0x44 and 0x48| |0x40|4|0| |0x44|4|offset to blank 8 bytes (0). Equals to offset 0x3C and 0x48| |0x48|4|offset to blank 8 bytes (0). Equals to offset 0x3C and 0x44| |0x4C|4|0| |0x50|4|0x78| |0x54|4|size of block 5 in 28-byte records| |0x58|4|offset of block 5| |0x5C|4|size of block 11 in 4-byte records. Equals block 10’s size * 2 (block 10 size is on 0x20 offset). Multiplying by 2 is for car files only. Common 3D objects in track files doesn’t multiply by 2 and doesn’t have a draw order section (block 11)| |0x60|4|offset of block 11| |0x64|4|Size of block 6 in 12-byte records (“smok”). Equals 0 or 1. 1 – player car. 0 – traffic car| |0x68|4|offset of block 6 (“smok”). Equals value on offset 0x70 minus 0xC. If “smok” is missing, value on offset 0x68 equals what is on 0x70 offset. Equals chunk length in bytes as on 0x04 offset for common 3D objects in track files. For traffic cars it points to ‘bott’ section, length = 0xC| |0x6C|4|size of block 7 in 12-byte records. Equals 0 for common 3D objects in track files| |0x70|4|offset of block 7. Equals chunk length in bytes as on 0x04 offset for common 3D objects in track files| |0x74|4|??? 0x120, 0x128, 0x130, 0x118 (Wagon.WrapFam car and common 3D objects in *_PKT_000)| **Fifth block** (28-byte records): ^offset^length^data| |00|8|identifier string ('NON-SORT', 'inside', 'surface', 'outside')| |0x08|4|0x8 for 'NON-SORT' or 0x1 for the others| |0x0C|4|number of polygons| |0x10|4|polygon sum data (see description by individual ('NON-SORT', etc.) sections below)| |0x14|4|0| |0x18|4|0| And as for every type of entry: 'NON-SORT': ^offset^length^data| |00|8|identifier string ('NON-SORT')| |0x08|4|0x08| |0x0C|4|equals block’s 10 size (total number of polygons)| |0x10|4|0| |0x14|4|0| |0x18|4|0| 'inside': ^offset^length^data| |00|8|identifier string ('inside')| |0x08|4|1| |0x0C|4|number of polygons for ???| |0x10|4|equals block’s 10 size| |0x14|4|0| |0x18|4|0| 'surface': ^offset^length^data| |00|8|identifier string ('surface')| |0x08|4|1| |0x0C|4|number of polygons for ???| |0x10|4|equals block’s 10 size + number of polygons from ‘inside’ = XXX| |0x14|4|0| |0x18|4|0| 'outside': ^offset^length^data| |00|8|identifier string ('outside')| |0x08|4|1| |0x0C|4|number of polygons for ???| |0x10|4|equals XXX + number of polygons from 'surface'| |0x14|4|0| |0x18|4|0| Total number of polygons in 'NON-SORT' equals sum in other sections:\\ 'NON-SORT' = 'inside' + 'surface' + 'outside'. Identifier string ‘outside’ and 0x0C offset affects rear tires draw order? 0x3 – rear right disappears, 0x2 – front right and rear right disappears, 0x1 two rear wheels and front right disappears, .\\ Changes in 0x10 offset changes polygons that doesn’t draw. **The sixth block**: ^offset^length^data| |00|8|identifier string (‘smok’)| |0x08|4|zero or 0x1F (Ferrari only). Doesn’t affect any performance| **The seventh block** consists of 12-byte records and describes tires, smoke and car lights: ^offset^length^data| |00|8|identifier string (rt_rear, rt_frnt, bklr, lt_rear, lt_frnt, bkll)| |0x08|4|texture index| Texture indexes referenced from records in block 10 and block 11th. Texture index shows that wheel or back light will be displayed on the polygon number defined in block 10. Smoke effect under the wheel will be displayed on drifting, accelerating and braking in the place where texture is shown. rt_rear – right rear wheel rt_frnt – right front wheel bklr – back light right lt_rear – left rear wheel lt_frnt – left front wheel bkll - back light left Cop’s car only: LOD 1: lfc0 - ????? lrc0 - ????? LOD 2, 3: lfr0 – ????? lfl0 – ????? hlr0 – ????? hll0 – ????? lrl0 – ????? lrr0 - ????? bkl0 – ????? bkr0 - ????? **The eighth block** consists of 12-byte records which describe the position in space of each vertex (using signed long integers, centered at (0,0,0)). ^offset^length^data| |00|4|x coord. (x axis is lateral)| |0x04|4|z coord. (z axis is vertical, z increases when going up)| |0x08|4|y coord. (y axis is longitudinal, increases when going forward)| **The tenth block **consists of 24-byte records and describes the polygons that are used to draw the car: ^offset^length^data| |00|1|polygon property. 0 - quadrangle, 1 - triangle, 4 – wheels (inside car textures)| |0x01|1|? 0xBF (Ferrari 512, Mazda RX7, Toyota Supra) or 0xDF (Lamborgini, Corvette ZR1, Dodge Viper) or 0xEF (Porsche 911, ANSX) or 0xCD (common 3D objects in scenery) or 0x1F (All ? traffic cars)| |0x02|1|0| |0x03|1|polygon flag (render order?)| |0x04|4|Index number. Max = block 10 size| |0x08|4|vertex 1 number| |0x0C|4|vertex 2 number| |0x10|4|vertex 3 number| |0x14|4|vertex 4 number| Polygon flag may be equal: 0x10 – one sided render?, 0x12 – one-sided render, but flipped normals 0x13 - two-sided render, 0x50 – one-sided render, 0x52 – one-sided render, but flipped normals, 0x51 – two-sided render (outside in fifth block??), 0x53 – two-sided render. Polygon flag may depend on fifth block? Two-sided renders over all polygons. You may edit only last number to test difference in game (0x*0, 0x*1, 0x*2, 0x*3)??. May be it’s a remainder check here when I try to divide it by 3. **The eleventh block** There are two parts in this block. First part is a sequence of 32-bit integers from 0 to block 10’s size (0, 0x1, 0x2, 0x3 …). Second part has the same size as a first one and also has a 32-bit ints, but their order is different. This order is a draw order for the polygons where the last int shows above all polygons in the game. **C)** **SHPM chunk (textures for the car)** These store the different bitmaps. The 16-byte header format is the following: ^offset^length^data| |00|4|'SHPM'| |0x04|4|length of the file in bytes| |0x08|4|number of objects in the directory| |0x0C|4|'SPoT'| This header is followed by the directory entries, each consisting of a 4-byte identifier string, and a 4-byte offset inside the file pointing to the beginning of the corresponding data. ^offset^length^data| |00|4|identifier string (‘0004’, ‘whl0’, etc.)| |0x04|4|offset to texture data relative to SHPM| 4-byte identifier string may have the following names. '0000 ', ' 0001 ', ' 0002'… - car’s textures. 'bkl1' – car back lights texture, ‘whl0’ – non-rotating wheels, ‘whl1’ –rotating wheels (animation type 1), ‘whl2’ –rotating wheels (animation type 2), 'bitf' – Rear car view, moderate distance, 'bitr' – Rear car view, closest distance just before switching to 3D car model, 'bits' – Rear car view, smallest pic and most far, 'mapv' – Small car image for the map (while paused), '!ori' – see section **C.1.** //Traffic cars only. //There are different palettes for one car, selected randomly by the game engine during gameplay. 'plt0' – palette 1, 'plt1' – palette 2, 'plt2' – palette 3, 'plt3' – palette 4, Cop’s car only: **LOD1**: ‘ lfr1’, ‘lfl1’, ‘lfl1’, ‘lrl2’, ‘lrl1’, ‘lrr1’, ‘lrr2’ – flashing lights textures **LOD2**: ‘ lfr1’, ‘lfl1’, ‘lrl1’, ‘lrl2’, ‘lrr1’, ‘lrr2’ – flashing lights textures **LOD3**: ‘ lfr1’, ‘lfl1’, ‘lrl1’, ‘lrl2’, ‘lrr1’, ‘lrr2’ – flashing lights textures Each directory entry in SHPM ('0000', '0001 ', '0002'…) points to a cel (CCB) block with the following structure. Note that there’s no CCB, PDAT, PLUT headers in the block. 16-byte header: ^offset^length^data| |00|2|0x400 – (CCB and PLUT headers type 1) 0x840 – (CCB and PLUT headers type 2) ???, 0x5FF – (CCB and PLUT headers type 3, traffic) ???, 0x500 – (CCB and PLUT headers type 3, traffic SASCO) ???| |0x02|2|local offset to the 32-color palette| |0x04|2|width of the bitmap in pixels| |0x06|2|height of the bitmap in pixels| |0x08|4|0 PREAMBLE word? CCB FLAGS? for player cars, non-zero for traffic cars| |0x0C|2|0x32| |0x0E|2|0x32| |0x10|various|bitmap cel data| Palette has the following structure: ^offset^length^data| |00|16|20 00 00 00 00 20 00 02 00 20 00 00 00 00 00 00| |0x10|64|palette data. 2 bytes per color| In order to make a correct cel file we must to complete all the headers. //CCB headers (type 1)// 43 43 42 20 00 00 00 50 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 D3 49 24 00 00 00 00 00 00 **00 08** 00 00 **00 **2050 44 41 54 __00 00 01 08__ … … Pixel data 50 4C 55 54 00 00 00 4C 00 00 00 20 … … Palette data **Bold numbers **are width and height, __underlined__ is the size of pixel data with PDAT header (+8 bytes!). For more information, see 3DO SDK (PLUT, PDAT, CCB headers). CCB headers (type 2) ??? **C.1)** '!ori' entry within the SHPM chunk is a texture selector for all polygons. N of entries = block 10th size. This block has the header and entries. Header size is 0x40: ^offset^length^data| |00|4|0x60 00 00 00| |0x04|1|4| |0x05|2|Block 10 size (see ‘ORI3’ structure) multiplied by 2 plus 12| |0x07|5|0| |0x0C|4|0x32 00 32 00| |0x10|4|1| |0x14|4|Polygon quantity. Same as block’s 10 size (see ‘ORI3’ structure)| |0x18|8|‘DEFAULT.’ identifier string| |0x20|4|Polygon quantity. Same as block’s 10 size (see ‘ORI3’ structure)| |0x24|4|1| |0x28|4|0| |0x2C|4|0x00 00 00 B0| |0x30|4|0| |0x34|4|0x00 00 01 08| |0x38|4|0x00 00 01 08| |0x3C|4|0| This block describes the link between the texture numbers in block 10 and the textures stored in the SHPI chunk. Each of the entries after ‘!ori’ header consists of 8-byte records and describes the polygon’s texture selector from block 10: ^offset^length^data| |00|4|Index number from block 10(see ‘ORI3’ structure)| |0x04|4|Texture index selector from SHPM header. Pointer to ‘0000’, ‘0001’, etc.| **D)** **TRACKS** TRACKs are consisting of two files located at: \DriveData\DriveArt and at: \DriveData\tracks **D.1)** DriveData\DriveArt\ files. These files contains scenery textures, horizon textures, object textures, 3D objects and textures. The file structure is the following: first a 24-byte header, then chunks. The header format is the following: ^offset^length^data| |**0** |**4** |**'wwww'** | |**0x04** |**4** |**Equals 5(number of chunks)** | |**0x08** |**4** |**0x1C (offset of the first chunk)** | |**0x0C** |**4** |**offset of the second chunk** | |**0x10** |**4** |**offset of the third chunk** | |**0x14** |**4** |**offset of the fourth chunk** | |**0x18** |**4** |**offset of the fifth chunk** | First 'wwww', then the number of chunks (as a long integer), then the offsets of each chunk header (long integers). The *_PKT_000 file itself is a 'wwww' file containing five chunks. The first chunk corresponds to the background bitmaps, making up the terrain and the road, while the second chunk is devoted to foreground bitmaps (road signs, etc…). Each of these two chunks is itself in 'wwww' format, containing sub-chunks. Note that the offsets of the sub-chunks listed in the headers are relative to the beginning of the chunks. **//This type of files consists of 5 chunks//:** **Scenery textures - 1st chunk** **Object textures - 2nd chunk** **3D objects - 3rd chunk** **Horizon textures - 4th chunk (bottom)** **Horizon textures - 5th chunk (top)** Al1_PKT_000 – Alpine, segment 1 Al2_PKT_000 – Alpine, segment 2 Al3_PKT_000 – Alpine, segment 3 Cl1_PKT_000 – Coastline, segment 1 Cl2_PKT_000 – Coastline, segment 2 Cl3_PKT_000 – Coastline, segment 3 Cy1_PKT_000 – City, segment 1 Cy2_PKT_000 – City, segment 2 Cy3_PKT_000 – City, segment 3 **First chunk **contain the bitmaps that are used for displaying the corresponding track segment. They make use of the 'wwww' file format, using the usual header. The first chunk starts with a ‘wwww’ header, which contains offsets to ‘wwww’ subchunks. All subchunks have 0x24 CCB entries. Texture numbers from ‘TRKD’ block refers to a corresponding entry number in the first ‘wwww’ header. Then it translates to the subchunk ‘wwww’ header. There are some texture LODs within subchunk, located at different offsets. **Second chunk** (object textures) has a usual ‘wwww’headerpointingatCCBentries. **The third chunk** describes the three-dimensional objects in the scenery. It is a 'wwww' structure, containing a subchunks. //First //‘wwww’ header defines a number of 3D objects stored in the 3rd chunk. //Second //‘wwww’ header defines three LODs of the current object, defined in the first ‘wwww’ header. Usually ‘ORI3’ sections in all LODs are equal. Difference is only in texture resolution and texture size, of course. Each LOD entry from the //second //chunk is a //third //‘wwww’ header consist of the two subchunks (ORI3 and SHPM). Each of these 3D objects is quite similar to a car file (For 3D objects format see car file format: section **A)** : it is itself a 'wwww' structure containing two subsubchunks! The first subsubchunk is an 'ORI3' structure describing the shape of the object, while the second is a 'SHPM' structure containing the bitmaps referenced by the 'ORI3' part. ‘ORI3’ header for common 3D objects see below. ^offset^length^data| |00|4|'ORI3'| |0x04|4|chunk length in bytes| |0x08|4|0x1F4| |0x0C|4|0| |0x10|4|size of block 8 in 12-byte records| |0x14|4|offset of block 8 = 0x78| |0x18|4|0| |0x1C|4|0x280| |0x20|4|size of block 10 in 24-byte records| |0x24|4|offset of block 10| |0x28|8|identifier string| |0x30|4|equals 0x20 offset (block 10 size)| |0x34|4|0| |0x38|4|0| |0x3C|4|offset to blank 8 bytes (0). Equals to offset 0x44 and 0x48| |0x40|4|0| |0x44|4|offset to blank 8 bytes (0). Equals to offset 0x3C and 0x48| |0x48|4|offset to blank 8 bytes (0). Equals to offset 0x3C and 0x44| |0x4C|4|0| |0x50|4|0x78| |0x54|4|size of block 5 in 28-byte records| |0x58|4|offset of block 5| |0x5C|4|size of block 11 in 4-byte records. Equals block 10’s size (block 10 size is on 0x20 offset). Common 3D objects in track files doesn’t have a draw order section (as for cars in the second part of block 11)| |0x60|4|offset of block 11| |0x64|4|Size of block 6 in 12-byte records. Equals 0 for common 3D objects| |0x68|4|offset of block 6. Value on offset 0x68 equals what is on 0x70 offset. Equals chunk length in bytes as on 0x04 offset for common 3D objects in track files| |0x6C|4|size of block 7 in 12-byte records. Equals 0 for common 3D objects in track files because block 7 doesn’t apply| |0x70|4|offset of block 7. Equals chunk length in bytes as on 0x04 offset for common 3D objects in track files because block 7 doesn’t apply| |0x74|4|??? 0x120 or 0x118| Identifier string on 0x28 offset tells us which LOD is it. For example, *T2000 – less-detailed model, fair textures *T1000 – medium detailed model, better textures *T0000 – full-detailed model, full-sized textures. ‘SHPM’ is reduced in comparsion with car files. **SHPM chunk (textures for the 3D object)** These store the different bitmaps. The 16-byte header format is the following: ^offset^length^data| |00|4|'SHPM'| |0x04|4|length of the file in bytes| |0x08|4|number of objects in the directory| |0x0C|4|'SPoT'| This header is followed by the directory entries, each consisting of a 4-byte identifier string, and a 4-byte offset inside the file pointing to the beginning of the corresponding data. ^offset^length^data| |00|4|identifier string (‘0001’, ‘0002’, etc.)| |0x04|4|offset to texture data relative to SHPM| 4-byte identifier string may have the following names. '0000 ', ' 0001 ', ' 0002'… - object’s textures. '!ori' – see section **C.1)**. To make a correct cel file from SHPM entry you must complete all the CCB headers (type 1), see **C)**. **The fourth and fifth chunk** of the *_PKT_000 file is a SHPM file describing the horizon. Fourth chunk is for the horizon’s bottom, fifth chunk is for the horizon’s top. Each chunk contains six CCB entries with ‘wwww’ header. **D.2) ** \DriveData\tracks. These files contains track’s geometry, objects size and location and virtual road for the game engine. al1.trk – Alpine, segment 1 al2.trk – Alpine, segment 2 al3.trk – Alpine, segment 3 cl1.trk – Coastline, segment 1 cl2.trk – Coastline, segment 2 cl3.trk – Coastline, segment 3 cy1.trk – City, segment 1 cy2.trk – City, segment 2 cy3.trk – City, segment 3 In order to understand the structure of TRK files you have to know that a track is the superposition of three structures: - first, a 'virtual road' : this is a sequence of points in space, which will be called 'nodes'. These points correspond to successive positions along the track, and all the cars have to pass near each of these positions. During the game, the virtual road is invisible, but you have to stay close to it. - second, the scenery : this is a collection of points in space, which will be called 'vertices', together with textures which are mapped onto the polygons defined by consecutive vertices. These textures are used to draw the road, the roadside and part of the landscape. Thus it is of course preferable that the scenery remain close to the virtual road ! - and last, the objects : points in space together with bitmaps, which are used for road signs, buildings, trees, etc… Some of them are plain 2D bitmaps, but others have a more sophisticated polygonal 3D structure. The 3D coordinates x,y,z will always be used with the following meaning : - x is an axis which is transversal to the starting line. Positive x values correspond to points which are on the right of the starting position. (i.e. if you start looking to the north, x points to the east) - y is an axis which is parallel to the starting line. Positive y values correspond to points which are ahead of the starting position. (i.e. y points to the north) - z is a vertical axis. Positive z values correspond to points higher than the starting position. These type of files consists of three chunks: Virtual road, Plain objects, Scenery and fences. They describe the track itself, including the shape of the road and the position of the scenery items. The objects are referenced by numbers which correspond to entries in the corresponding file in DriveData\DriveArt\. a)** TRK files** begin with 0x13B4 bytes of headers and index tables. These are as follows: ^offset^length^data| |00|4|0xE| |0x04|4|scenery block number (see** D.2.3**) of the ending (checkpoint, finish) line + 45. If you want to see what is happening behind the checkpoint line after finish, set: \\ Alpine, segment 1 – 0x231 \\ Alpine, segment 2 – 0x26B \\ Alpine, segment 3 – 0x247 \\ Coastline, segment 1 – 0x208 \\ Coastline, segment 2 – 0x1F5 \\ Coastline, segment 3 – 0x1F5 \\ City, segment 1 – 0x208 \\ City, segment 2 – 0x1E1 \\ City, segment 3 – 0x24F| |0x08|4|0x60000| |0x0C|4|x coordinate of the first node| |0x10|4|z coordinate of the first node| |0x14|4|y coordinate of the first node| |0x18|4|0| |0x1C|4|0| |0x20|4|0| |0x24|4|length of the scenery data in bytes (All TRKD sections, from first TRKD till the end of file)| |0x28|4|1| |0x2C|0x960|**first index table** | |0x98C|0x960|**second index table** | |0x12EC|4|??????| |0x12F0|0x80|????? third index table. All tracks except Coastline segment 1 have this table filled with 0xFF| |0x1370|0x40|????? Filled with zeroes except Coastline segment 1 track| |0x13B0|4|0x3F| **The first index table** is a succession of 32-bit offsets. It follows a progression by size of each scenery TRKD entry. This means the first value is 0, followed by block 1 TRKD size, block 2 TRKD size + block 1 TRKD size, etc… Sometimes this progression interrupts with zero entry when value is greater than 0x1C000???\\ The table is filled to 960h bytes (600 entries) with zero values. This table is probably only used as a lookup table in memory during the game. **The second index table **is also a succession of 32-bit offsets, but these offsets are inside the TRK file. Each offset points to TRKD block (see section **D.2.3**). It corresponds to the offsets of the successive records for scenery data, which starts at offset 1B000h in the scenery file. It is filled to 600 entries with zero values. \\ **D.2.1)** Virtual road section for the 3DO version starts at 0x13B4 finish at 0x16534\\ b) The virtual road data follows, and is constituted of 36-byte records\\ (one for each node). The first record is at offset 13B4h, and records ends at offset 16534h (this leaves room for 2400 records, and since a scenery block corresponds to four nodes, both capacities are equal).\\ The unused records (after the last node) are filled with zero values.\\ The structure of each record is the following: ^offset^length^data| |00|1|a0| |0x01|1|a1| |0x02|1|a2| |0x03|1|a3| |0x04|1|b0| |0x05|1|b1| |0x06|1|b2| |0x07|1|b3| |0x08|4|x coordinate| |0x0C|4|z coordinate| |0x10|4|y coordinate| |0x14|2|slope| |0x16|2|slant-A| |0x18|2|orientation| |0x1A|2|0| |0x1C|2|y-orientation| |0x1E|2|slant-B| |0x20|2|x-orientation| |0x22|2|0| - a0,a1 are 8-bit values. Those shows width of the road to the left and right verges.\\ - a2, a3 are 8-bit values. Those are for left and right invisible barriers of the road. - b0,b1,b2 are 8-bit flags.\\ b0 – Traffic direction and distance between lanes?\\ 0-forward only, two lanes.\\ 1-forward only, right lane/lanes.\\ 2-forward only, right lane/lanes (may occupy right verge). b1 – barrier type and sound? Fence distance?\\ b2 – barrier type and sound? Verge type and sound?\\ - b3 is 8-bit flag for future use with ParseScenery (Tracknode property). It defines tunnels on the left or on the right, lanes split and rejoin.\\ b3 = LANE_SPLIT = 0. Used in Alpine, Coastal tracks when the road widens. Vertices should be moved to the right (see scenery block **D.2.3**).\\ b3 = LANES_3 = 1(?). Road lanes = 3.\\ b3 = LANES_2 = 3 (?). Road lanes = 2.\\ b3 = LANE_REJOIN = 2. Used in Alpine, Coastal tracks when the road narrows. vertices should be moved to the right (see scenery block **D.2.3**).\\ b3 = TUNNEL_1 = 4. plays tunnel sound and car textures are faded a bit.\\ b3 = BRIDGE = 5. plays bridge sound at Alpine 2 track and car textures are not faded. Check flag on other track.\\ b3 = TUNNEL_2 = 7. plays tunnel sound at Coastal 2 track and car textures are faded a bit (?).\\ b3 = TUNNEL_3 = 8. Forest at Coastal 3 track and car textures are faded a bit (?).\\ b3 = TUNNEL_4 = 9. plays bridge sound at Alpine 3 track in tunnels with windows. No car textures fading occurs. \\ The next properties are interesting! If set, either the last terrain strips on the right or left is detached and placed between the specified points. This is how the tunnels in Coastal and Alpine 3 are constructed.\\ b3 = RIGHT_TUNNEL_A2_A9 = 7.\\ b3 = LEFT_TUNNEL_A4_A9 = 9.\\ b3 = LEFT_TUNNEL_A9_A5 = 13.?? \\ - x, z and y coordinates are signed long values. - slope is a value indicating the slope at the current node, i.e. the difference between the z coordinates of two consecutive nodes.\\ A good approximation is : slope(i) = (z(i+1) - z(i))/152. However, to complicate things, it is stored as a signed 14-bit value, complemented to 4000h. This means -1 is stored as 3FFFh, -2 as 3FFEh, … So in fact you must perform a logical and with 3FFFh before storing ! - slant-A is a value indicating how the road is slanted to the left or to the right (as in the turns in Autumn Valley or Lost Vegas). It is a signed 14-bit value, like slope. The value is positive if the road is slanted to the right, negative if it is slanted to the left. - slant-B has the same purpose, but is a standard signed 16-bit value. Its value is positive for the left, negative for the right. The approximative relation between slant-A and slant-B is slant-B = -12.3 slant-A (remember that slant-A is 14-bit, though) - orientation is a 14-bit value, and is equal to 0 for north (increasing y), 1000h for east (increasing x), 2000h for south (decreasing y), 3000h for west (decreasing x), and back to 3FFFh for north. - y-orientation is a signed 16-bit value, which is proportional to the y coordinate variation. Meanwhile, x-orientation is proportional to the\\ *opposite* of the x coordinate variation. This means that the couple (-xorientation,yorientation) gives the orientation of the track.\\ The norm (square root of xorient^2+yorient^2) is usually around 32000 (a little less than 8000h, to avoid numeric overflows), but can fluctuate\\ with the only condition that (-xor,yor) gives the correct orientation. \\ **D.2.2**) Objects startOffset = 0x17050; paramsStart = 0x16C3C;\\ c) The objects data comes next: ^offset^length^data| |0x16534|0x708|3-byte records for the traffic (there are 600… as many as scenery blocks)| |0x16C3C|4|0x40 = Number of 16-bytes entries (object parameters data)| |0x16C40|4|0x3E8 = 1000 (size of the main block in records)| |0x16C44|4|'OBJS'| |0x16C48|4|0x428C (total length of the remaining blocks)| |0x16C4C|4|0 ??| |0x16C50|0x400|16-byte records (Object parameters data)| |0x17050|0x3E80|object data: 1000 records of 16 bytes (one per object)| |0x1AED0|0x130|0| 0x708 - are a 3-byte records affects traffic cars speed and trigger speed for the cops. If set to zero, forward-moving traffic cars will generate at the distance and will be just standing on the road. If set to 0xFF, forward-moving traffic cars will speed up to approx. 100 mph. These 3-byte records have the following structure: May be if I’ll set another value on 0x16C3C offset and recalculate others I can extend all object parameters entries? ^offset^length^data| |00|1|Traffic car speed| |0x01|1|Cops trigger speed| |0x02|1|Traffic car speed| **Object parameters data** (0x400, 16-byte records) describes width, height of the object, it’s type and a flags. Each record is 16-byte long. ^offset^length^data| |00|1|SceneryFlags (none = 0, animated = 4 (only for PC version)| |0x01|1|SceneryType model = 1, bitmap = 4, twosidedbitmap = 6 (two bitmaps, one is turned by 90 degrees)| |0x02|1|Resourse ID| |0x03|1|Resourse ID2 for 2-sided bitmap object| |0x04|1|0| |0x05|1|width| |0x06|7|?????| |0x0D|1|height| |0x0E|1|?????| |0x0F|1|0| These parameters are linked with object data (see below) started from 17050 offset. **The object data **itself consists of a 16-byte record per object. The record structure is the following: ^offset^length^data| |00|4|reference node| |0x04|1|bitmap number| |0x05|1|flip| |0x06|4|flags (unknown purpose) ??????| |0x0A|2|relative x coordinate| |0x0C|2|relative z coordinate| |0x0E|2|relative y coordinate| Object data entry for each object must be considered with object’s parameters entry. Object’s bitmap number equals entry number in object’s parameters block. ResourseID, resourseID2 from object’s parameters sections refers to object texture in 2nd chunk *_PKT_000 file using ‘wwww’ header. Number of entry = resourseID (resourseID2) number. Each object is related to a reference node in the virtual road. The x,z,y\\ coordinates are then expressed as signed 16-bit values relative to the\\ coordinates of the reference node. Beware that the axes are simply translated\\ but not rotated! (i.e. the x and y axes are still pointing east and north)\\ The objects are sorted in the order of increasing reference nodes.\\ A reference node value of -1 indicates that the record is unused (i.e. after\\ the end of the used records). Also note that the coordinates are not\\ expressed in the same unit as the 32-bit absolute coordinates seen above\\ (the units are much larger, so that the value fits in 16 bits). The 8-bit flip value is equal to 0 for an object that is perfectly perpendicular to the track (e.g. a road sign), larger values for objects that are slightly turned, until 64 for an object that is mapped along the track (e.g. an ad on the side of the road), then up to 128 which is the perfectly reversed position (since the objects have no "back", this is the common way of reversing a road sign for a turn in the other direction), then\\ up to 192 which is again longitudinal mapping (the other way) and until 255 which is back to the normal position. **D.2.3**) Scenery and Fences startOffset = 0x1B000;\\ d) The scenery data starts at offset 1B000h. It is made up of different sized records, each corresponding to four nodes in the virtual road. The records are consecutive and the last record ends the .TRK file.\\ Each record has the following structure: ^offset^length^data| |00|4|'TRKD'| |0x04|4|length of the record contents (with CCB section)| |0x08|4|number of this record (0 for the first, then 1, etc…)| |0x0C|1|????? May be non-zero once on the track and at the last ‘TRKD’ block. Block #1 within TRKD started here. Size = 0x258| |0x0D|1|Fence present. Stores the sides of the road the fence lives, and the textureId to use for it. If the top bit is set, fence on the left exists, if next bit is set, fence is on the right. Both can also be set. The other 6 bits seem to the texture number.| |0x0E|10|10 textures (one byte per texture)| |0x18|12|reference point (A0 point)| |0x24|12|Coordinates? Marker where ends current block sized 0x2DC? End 0x84 sized overlapping. Appears at 0x24 offset, second and the last position – before CCB minus 0x50. It means: CCB – 0x50 – 0x2DC + 0x84 = second these bytes position end.| |0x30|12|point A0| |0x3C|12|point A1| |**…** |**…** |**…** | |0x9C|12|point A9| |0xA8|12|point A10| |0xB4|12|not used?| |0xC0|12|point B0| |0xCC|12|point B1| |**…** |**…** |**…** | |0x12C|12|point B9| |0x138|12|point B10| |0x144|12|not used?| |0x150|12|point C0| |0x15C|12|point C1| |**…** |**…** |**…** | |0x1BC|12|point C9| |0x1C8|12|point C10| |0x1D4|12|not used?| |0x1E0|12|point D0| |0x1EC|12|point D1| |**…** |**…** |**…** | |0x24C|12|point D9| |0x258|12|point D10| |0x264|1|? Block #2 within TRKD started here. Block #2 size is 0x258| |0x265|1|fences again| |0x266|10|Textures again| | | | | |0x270|12|point E0| |0x27C|12|? Purpose is the same as on 0x24 offset, but values are from????| |0x288|12|point A0 (next TRKD subblock) = E0 point. This offset is a A0 point for the next scenery block. It means, that points data for the current and next block is overlapped. E10 point for the current block (n) ends at 0x30C since A0 point for the next block (n+1) starts at 0x288. Data for the (n+1) block is located between 0x288 and 0x564 offsets. As mentioned before 0x84 bytes for the connected blocks are overlapped. For the (n+1) and (n+2) blocks overlapped by the same way. In other words, points E10-E0, E1-E5 from n block equals A10-A0, A1-A5 points from n+1 block. \\ Size 0x84 explanation: 11 points total overlapping. X,Y,Z coordinates (4 bytes each) = 12 bytes 1 point. 12*11=132=0x84. \\ If any of the X or Y or Z values and doesn’t differs a lot with D0 X or Y or Z point and number of this record is more than 100, E0 point is on 27C offset??? And reference point on 0x18 offset is E0 point from (n-1) offset????| |0x294|12|point E1=A1 (n+1)| |**…** |**…** |**…** | |0x2F4|12|point E9=A9 (n+1)| |0x300|12|point E10=A10 (n+1)| |0x30C|7032|Points for 12 forward-located blocks. See 0x288 offset for more information| |0x1E84|780|Five blocks sized 0x9C (see small blocks structure below). \\ Rest of the space is filled with zeros| |0x2190|80|Block 80. See below for structure. In some cases, there are additional bytes after Block 80: \\ 4F 46 53 54 00 00 00 18 00 00 00 68 00 00 00 B4 00 00 00 D4 00 00 00 EC \\ (‘OFST’ identifier string, 0x18, 0x68, 0xB4, 0xD4, 0xEC).| |0x21E0|various size|CCB texture. Unused space after CCB texture is filled with 0 to fill the modulus (see below). \\ Size of ‘TRKD’ block must be aligned to 0x1000 or 0x800 offset as the follows. Possible sizes of ‘TRKD’ blocks are: 0x2000, 0x2800, 0x3000, 0x3800, 0x4000, 0x5000, 0x6000, 0xC000, 0x8800, 0xA000 and so on.| **Small blocks** structure:\\ There are 5 blocks:\\ __Block 1:__ ^offset^length^data| |00|2|Equals zero. (Not used)| |0x02|10|10 textures (one byte per texture) for the n+1 block| |0x0C|12|Point coords. Purpose is the same as on 0x27C offset, but values are from????| |0x18|12|A0 point for the n+1 block| |0x24|12|A1 point for the n+1 block| |0x30|12|A2 point for the n+1 block| |0x3C|12|A3 point for the n+1 block| |0x48|12|A4 point for the n+1 block| |0x54|12|A5 point for the n+1 block| |0x60|12|A6 point for the n+1 block| |0x6C|12|A7 point for the n+1 block| |0x78|12|A8 point for the n+1 block| |0x84|12|A9 point for the n+1 block| |0x90|12|A10 point for the n+1 block| __Block 2: __ ^offset^length^data| |00|2|Equals zero. (Not used)| |0x02|10|10 textures (one byte per texture) for the current block| |0x0C|12|Point coords. Purpose is the same as on 0x27C offset, but values are from????| |0x18|12|A0 point for the current block| |0x24|12|A1 point for the current block| |0x30|12|A2 point for the current block| |0x3C|12|A3 point for the current block| |0x48|12|A4 point for the current block| |0x54|12|A5 point for the current block| |0x60|12|A6 point for the current block| |0x6C|12|A7 point for the current block| |0x78|12|A8 point for the current block| |0x84|12|A9 point for the current block| |0x90|12|A10 point for the current block| __Block 3:__ ^offset^length^data| |00|2|Equals zero. (Not used)| |0x02|10|10 textures (one byte per texture) for the n-1 block| |0x0C|12|Point coords. Purpose is the same as on 0x27C offset, but values are from????| |0x18|12|A0 point for the n-1 block| |0x24|12|A1 point for the n-1 block| |0x30|12|A2 point for the n-1 block| |0x3C|12|A3 point for the n-1 block| |0x48|12|A4 point for the n-1 block| |0x54|12|A5 point for the n-1 block| |0x60|12|A6 point for the n-1 block| |0x6C|12|A7 point for the n-1 block| |0x78|12|A8 point for the n-1 block| |0x84|12|A9 point for the n-1 block| |0x90|12|A10 point for the n-1 block| __Block 4:__ ^offset^length^data| |00|2|Equals zero. (Not used)| |0x02|10|10 textures (one byte per texture) for the n-2 block| |0x0C|12|Point coords. Purpose is the same as on 0x27C offset, but values are from????| |0x18|12|A0 point for the n-2 block| |0x24|12|A1 point for the n-2 block| |0x30|12|A2 point for the n-2 block| |0x3C|12|A3 point for the n-2 block| |0x48|12|A4 point for the n-2 block| |0x54|12|A5 point for the n-2 block| |0x60|12|A6 point for the n-2 block| |0x6C|12|A7 point for the n-2 block| |0x78|12|A8 point for the n-2 block| |0x84|12|A9 point for the n-2 block| |0x90|12|A10 point for the n-2 block| __Block 5:__ ^offset^length^data| |0|2|Equals zero. (Not used)| |0x02|10|10 textures (one byte per texture) for the n-3 block| |0x0C|12|Point coords. Purpose is the same as on 0x27C offset, but values are from????| |0x18|12|A0 point for the n-3 block| |0x24|12|A1 point for the n-3 block| |0x30|12|A2 point for the n-3 block| |0x3C|12|A3 point for the n-3 block| |0x48|12|A4 point for the n-3 block| |0x54|12|A5 point for the n-3 block| |0x60|12|A6 point for the n-3 block| |0x6C|12|A7 point for the n-3 block| |0x78|12|A8 point for the n-3 block| |0x84|12|A9 point for the n-3 block| |0x90|12|A10 point for the n-3 block| **Block 80**. This block is for CCB reference point, CCB size, CCB position on the screen when car is on the n block. ^offset^length^data| |00|4|Point A0X (block n+12)| |0x04|4|Point A0Z (block n+12)| |0x08|4|Point A0Y (block n+12)| |0x0C|4|Point A6X (block n+20)| |0x10|4|Point A6Z (block n+20)| |0x14|4|Point A6Y (block n+20)| |0x18|4|Point A0X (block n+22)| |0x1C|4|Point A0Z (block n+22)| |0x20|4|Point A0Y (block n+22)| |0x24|4|0| |0x28|4|0| |0x2C|4|0| |0x30|4|Cel background position X?| |0x34|4|Cel background position Y?| |0x38|4|not used ?| |0x3C|4|not used ?| |0x40|4|not used ?| |0x44|4|not used ?| |0x48|4|0x10001| |0x4C|4|CCB size in bytes| Each point is given by three signed 32-bit absolute coordinates (x,z,y as usual). The coordinates are the same as in the virtual road data. The reference point is unused in the game and usually equal to point A0. The points A0,…,A10 in record #n (starting with 0) correspond to the node #4n (starting with 0) in the virtual road data. B0,…,B10 correspond to node #4n+1, C0…C10 to node #4n+2, D0…D10 to node #4n+3 and E0…E10 to node #4n+4. Thus the points E0…E10 are identical to the points A0…A10 of the following record. The eleven point series (0 to 10) are arranged as follows: A0-E0 are near the middle of the road, and thus close to the corresponding nodes. A1-E1 are a little to the right, A2-E2 further right, … until A5-E5. A6-E6 are a little to the left, A7-E7 further left, … until A10-E10.(In tunnels, the points A5-E5 and A10-E10 get back to the center, constituting the ceiling).\\ To each record correspond ten textures (coded at the beginning), each given by a 8-bit value, T1,T2,…,T10. T1 is used between A0-E0 and A1-E1, T2 between A1-E1 and A2-E2, …, T5 between A4-E4 and A5-E5 ; meanwhile, T6 is used between A0-E0 and A6-E6, T7 between A6-E6 and A7-E7, …, T10 between A9-E9 and A10-E10. This is summarized on the following diagram: {{:documentation:file_formats:images_for_nfs_files_format:точкиscenery-model.jpg?nolink&1600x1280|точкиscenery-model.jpg}} The texture numbers are converted to bitmaps in the first chunk of the *_PKT_000 file (see **D.1**). **E) Other image files.** \\ There are also many other image files located at: \FrontEnd\Display. These are *.3sh files each containing one or some SHPM chunks (bitmaps). The 16-byte header format is the following: ^offset^length^data| |00|4|'SHPM'| |0x04|4|length of the file in bytes| |0x08|4|number of objects in the directory| |0x0C|4|'SPoT'| This header is followed by the directory entries, each consisting of a 4-byte identifier string, and a 4-byte offset inside the file pointing to the beginning of the corresponding data. ^offset^length^data| |00|4|identifier string (‘eal2’, ‘512b’, etc.)| |0x04|4|offset to texture data relative to SHPM| 4-byte identifier string may have different names. Each directory entry in SHPM (‘eal2’, '512b’, …) points to a cel (CCB) block with the following structure. Note that there’s no CCB or PDAT headers in the block. 16-byte header: ^offset^length^data| |00|2|0x9600 for CCB headers type 3, or 0x1600 for CCB headers type 3a. Other values possible?| |0x02|2|0| |0x04|2|width of the bitmap in pixels| |0x06|2|height of the bitmap in pixels| |0x08|4|0 (?)| |0x0C|2|???| |0x0E|2|???| |0x10|various size|bitmap cel data| In order to make a correct cel file we must to complete all the headers.\\ __CCB headers (type 3)__ \\ 43 43 42 20 00 00 00 50 00 00 00 00 7F 6F 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 1F 00 1F 00 80 00 3B D6 00 9E 01 3F 00 00** 00 70** 00 00** 00 31** 58 54 52 41 00 00 00 20 00 00 00 02 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 50 44 41 54 __00 00 18 C8__ \\ … … Pixel data __CCB headers (type 3a)__ \\ 43 43 42 20 00 00 00 50 00 00 00 00 7F 6F 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 1F 00 1F 00 80 00 3B D6 00 9E 01 3F 00 00 **01 40** 00 00 **00 F0** 58 54 52 41 00 00 00 20 00 00 00 02 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 50 44 41 54 __00 02 58 08__ \\ … … Pixel data **Bold numbers** are width and height, __underlined __is the size of pixel data with PDAT header (+8 bytes!). For more information, see 3DO SDK (PDAT, CCB headers).