The TrakSim Data File Format


TrakSim reads a data file containing the (encoded) track specification, which it uses to generate the simulated camera image. Included in this distribution is a sample file encoded from the PatsAcres go-kart track map downloaded from the internet. Also included is a sample track descriptor file, which TrakSim can read to generate an array of numbers to create a replacement track specification data file using the BuildMap API. Ordinarily you do not need to delve into the internal structure of this data file unless you want to add features not (yet) supported in this distribution.

The file is divided into three parts, which get separated when the file is read. The first part is a three-number header that specifies the byte ordering ("Big-Endian" or "Little-Endian") of the rest of the file, so that the file can be constructed and later used on computers with different native architectures, and the size of the index and image parts, which follow.

Big-Endian files start with the (ASCII) letters 'B', 'i', 'g', and 'E' in four separate bytes as a single number. Little-Endian files begin with the letters 'L', 'i', 'l', and 'E' in the same positions. The 'B' or 'L' is always the first byte of the file, but if the file is read as integers, it may appear in the high eight bits ("big end") or the low eight bits ("little end") of that integer, depending on the hardware. All the remaining numbers are integers encoded as specified.

Back to front of TrakSim

The Index Part

The index part of the file is divided into five segments: the Global Parameters, the Artifact Index, the Grid Map, the Paint Index, and the Paint Map, each discussed in their own section here.

Global Parameters

There are exactly eight integers in the global parameter section of the file, here discussed by its offset within the index part (add +3 for file offset).

+0 -- Images Part dimensions in pixels, tall shifted left 16, + wide (this is the normal and logical packing of a Point or rectangular size in the original Macintosh operating system). Use zero if there are no artifacts and no images part.

+1 -- Texture index, currently zero because we do not support textures in this release.

+2 -- Offset (within the index part) of the Grid Map, which also marks the end of the Artifact Index. Because the grid map is a hard-coded size 100 2-meter units N-S by 128 units E-W (=12800 integer grid cells), this also defines the beginning of the Paint Index., or else the end of the index part if no paint is defined.

+3 -- Park dimensions in scaled meters, which must be not greater than 200 meters by 256 meters.

+4 -- Grounds Colors, the basic track color in the low half, and the off-track color in the high half. See "Global Park Properties" in the documentation on "Building Your Own Track" for an explanation of the encoding.

+5 -- Start Position of simulated car, in park meters south of the top edge of the map, shifted left 16, + meters east of the left edge of the map.

+6 -- Car Orientation in degrees + Track Line Width in centimeters, shifted left 16. All directions in TrakSim are in degrees clockwise from north. If the specified track line width is zero or unreasonable, the default line width (see WhiteLnWi) is used.

+7 -- Offset (within the index part) of the Paint Map, or else zero if no paint is defined. The Paint Index is searched backwards from this offset. The paint map (if there at all) is the end of the index part.

Artifact Index

The artifact index is divided into three segments, each terminated by one or more zeros. If there are no artifacts, the first zero terminator is sufficient. In the first section are listed all the artifacts to be displayed in every frame, each as a sequence of four integers, plus (first) a tagged offset to each animated artifact timelines sequence, plus two integers defining each timing sequence start. The second section consists of one or more zero-terminated timelines, lists of offsets and expiration times for all the images of any animated artifacts in that timeline, and the third section contains the four integer specifications for those animated artifacts.

Each artifact is completely defined by four integers:

+0 -- Grid Location in 25cm units, V<<16 + H, with an artifact reference number in the high four bits.

+1 -- View Angle in clockwise degrees from north, + Range of view in degrees spanning that view angle (shifted left 16), or else zero if this image is visible from any angle. The list of artifacts is searched sequentially, and all artifacts at the same grid location are assumed to be the same artifact as seen from different view angles (different positions of the simulated car). Artifacts not in view are omitted from consideration, both if they are behind the simulated car, or else the car is not within the specified view angle and range.

+2 -- Image Offset + Pixels per Meter (PPM) shifted left 24. The image offset is in absolute integers from the top-left of the image part of the file, and refers to the center of the bottom row of that image, because images are drawn centered on the specified coordinate wherever it appears in the generated image, and upward, thus obscuring any artifacts behind it. The images are drawn scaled according to the distance from the viewer and the specified PPM. Lower resolution images are simply blockier when seen close-up. Scaling is achieved by replicating or skipping pixels, not by blurring partial pixels, because this is done in Java, not in a high-speed graphics engine.

+3 -- Height<<16 - half-Width in file pixels. The file format was originally specified to also handle background mattes, but they got triaged out for this release. The negative width can be thought of as the number of pixels from the specified offset back to the left edge of the image, which is also the negative of the number of pixels to the right edge of the image. As much of the entire rectangle is drawn as can be seen on the screen, but negative ints in the file are considered transparent and omitted.

A timing sequence is defined by two integers:

+0 -- Grid Location in 25cm units, V<<16 + H, with an artifact reference number =4 in the high four bits, and a 4-bit code shifted left 12 bits, which code specifies how to compare the car position to the grid location to determine if this timeing sequence should be activated. Bit +8 (if set) requires the vertical position of the car to be greater than (south of) the high 16-bit grid position; +4 (if set) requires the vertical position of the car to be less than (north of) the high 16-bit grid position. Similarly, +2 (if set) requires the horizontal position of the car to be greater than (east of) the low 16-bit grid position; +1 (if set) requires the horizontal position of the car to be less than (west of) the low 16-bit grid position. Obviously incompatible bits combinations will render the timing specification useless, as will a zero in all four bits.

+1 -- Sequence # <<16 + Start Time in seconds. The current sequence number is initially set to zero, and only a Timing Sequence specified for sequence #0 can activate. Once it does, only #1 can activate, and so on. It has not been tested, but it seems probable that multiple Timing Sequences specified for the same sequence # would all be tested in turn, and the first to activate advances to the next number. In any case, the specified start time becomes the current time for comparison to all the animated artifacts' expiration times. If you start a new sequence earlier than the one it replaces, then all currently active animations will pause until the time catches up to their current expiration times, so it's probably not a useful thing to do.

Animated (time-sensitive) artifacts are represented in the first section of the index each by an anchor, a single integer at the front of the section containing an offset to its respective timeline plus the reference number (in the range 5-15) in the high four bits.

The timelines in the second section are each an ordered sequence of integers, where the low half is an expiration time in 125ms (1/8th second) units (or zero if the final image is to remain after the animation terminates), and the upper half is an offset to the image specification for this time slot in the animation. Each timeline is reached from its anchor at the front of the first section, so these timelines could be anywhere in the file, but a single timeline must be contiguous and zero-terminated.

The third section is all the image specifications linked from their timelines, in no particular order. Because only 15 bits are available to link to them, these must be before the grid map.

Grid Map

Each cell of the grid map defines the contents of one 2x2-meter square of the track park. Most of the time this is a single unit of off-track "grass" or out-of-park "outer darkness" or track interior, each with no further qualification. The track edges, however are more precisely defined, so the grid cells that cross a track edge are defined with the coefficients of a line equation representing the track edge through that grid cell.

A track edge cell is a negative integer with two more bits defining whether the line is more vertical or horizontal, and whether the track is greater or less than the line equation evaluation. The line equation (for the vertical form) is mx+y+k, where x and y are the coordinates of a point on the line, and m and k are the coefficients, encoded as fixed-point representations of their respective fractional values. The horizontal form reverses x and y, but is otherwise the same. 45-degree lines have m=0.999 (rounded to 1.0) or =-1.0, and vertical (or horizontal) lines have m=0. The low eleven bits of the cell value encode the sign and fraction of m, and the next 18 bits encode k with a precision of eight bits to the right of the binary point, nine bits to the left, plus a sign, for a dynamic range +/-511 and a precision of about 3mm (although roundoff error makes the accuracy somewhat worse than that). The calculation is pretty quick, a small number of shifts to extract the parts, followed by a couple floating-point multiplies and an add, both of which execute in a single clock cycle on modern pipelined computers. Any point in the grid cell can be evaluated by the line formula and return a signed value "in or out" of the track. This happens only for track edges that are on display, typically two per raster line (unless you have the map showing), once each pixel touching that edge.

Paint Map

The paint map (if there at all) is one bit for each square meter of the grid map, so it also is a fixed size, 6400 integers representing 200x256 bits, packed 32 horizontal bits per integer. A bit is one if that square meter has any paint (including transparent) and zero otherwise, so that the paint index is not searched for parts of the display that are unpainted.

Paint Index

The paint index is sort of like the artifact index, three integers for each separate image in the images part, searching backwards from the beginning of the paint map, and ending when the dimensions are zero:
-1 -- Dimensions, Tall<<16 + Wide, both in image pixels.

-2 -- Location, Vertical<<16 + Horizontal, both in 25cm 1/8th grid coordinates.

-3 -- Image Offset + Options<<24; the image offset is to the top-left corner of the rectangular image being painted starting at the northwest corner specified in Location.

The +04 bit of the options byte =0 for low-resolution (each pixel of the image is one 25cm square on the ground), or non-zero for high-resolution (each pixel of the image fills a 3cm square of ground). In either case, the image is scaled in perspective for the distance of the viewer, with excess pixels discarded or needed additional pixels replicated from their nearest neighbor, without blurring partial pixels.

The low two bits of the options byte define image rotation in multiples of 90 degrees clockwise (00 means the image is oriented on the ground as it is in the image file, 01 is rotated 90 degrees clockwise, etc). When the image is rotated, the location still refers to the northwest corner of the image as painted, but the pixels count backwards from the top-left corner of the file image, which may be in some other corner of the map than the specified northwest; if the image is low-res, the pixels map exactly to grid location, but in hi-res, if the height and/or width are not exact multiples of eight pixels, the effect of counting backwards from the top-left corner of the file image as rotated can result in unexpected location offsets.

The Images Part

The images part of the data file (if present) is exactly in the format of a single-strip data portion of a Tiff32 file of the same dimensions. Unlike Java RGB data structures, where the blue byte is the least-significant eight bits of the integer, in Tiff files that position is reserved for the alpha mask. Or rather, the image is considered to be an array of bytes regardless of the Endian-ness of the hardware, and the first byte is the red byte of the first pixel, and the fourth byte is the alpha channel. TrakSim assumes only one transparent code, FF,FF,FF,FF; all other colors are encoded as RR,GG,BB,00. none of the header information of the Tiff file is preserved, but the height and width are separately carried in the index.

For more information on the Tagged Image File Format see the Aldus/Microsoft Technical Memorandum dated 8/8/88.

Tom Pittman
Rev. 2018 May 22