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.
+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.
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.
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.
-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.
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