TFX Research archive

Environment palette bindings and colour remaps

The palette-environment viewer displays the results of executing TFX 2.05's original environment parser at 0x747fc. 33 of the 39 retained grid names have usable configurations. For each, the capture records palette filenames, destination banks, mode flags, schematic binding, and seven numerical distance fields. Archive reads, allocation, the resource-root prefix and a fixed time input are supplied by the harness; these are configuration captures rather than rendered flight scenes.

The other six names are clouds, columbia, libya, seaworld, somalia and yugoslav. Five have no matching configuration text, while columbia is rejected as an invalid game type. These include authoring/base grids; they are not presented as six broken playable missions. Exact native errors and partial loads remain in environments.json.

Normal palette banks occupy data offsets 0x21000, 0xf688, 0xf388, 0xf088 and 0xed88. Darkside configurations load additional banks at 0x10888, 0x10588, 0x10288, 0xff88 and 0xfc88. All 33 successfully parsed TFX configurations also provide an infrared palette at 0xea88; the parser’s inferno token appears in normal TFX regional configurations too. Multiple banks can deliberately use the same file. Night and darkside flags are retained separately; a fixed-time capture does not reproduce time-varying transitions.

The native night-light flag lives in the code object's shape status word at offset 0x47c82, bit 0x0080; it is not a field at that offset in the C data object. Captures retain both shape_status and night_flag. All 33 decoded configurations match their explicit night token, including twilight environments. City and runway shape programs test this bit to draw their authored amber/pale-yellow dots; the map viewer and mechanism notes now expose them.

The fields at 0x10bc8, 0x10bd0, 0x10bcc, 0x10b9c and 0x10b98 are now confirmed as altitude palette boundaries by the native consumer 0x73214, which compares them with negated camera-anchor Y at 0x134f8. It blends the five banks in integer 50-stage steps, with a retained cached blend value and a target-view exclusion. The C++ reconstruction compares every resulting palette byte and retained state across 4,224 supplied-state updates in all 33 environments. The remaining 0x10b8c / 0x10b90 fields belong to the separate darkside traversal path; that path is outside the TFX altitude-palette comparison.

Native startup 0x73f5c prepares a magenta sentinel palette, then 0x73964 fills its protected colour entries from the executable table. 0x73a0c overlays those entries using the player pitch/roll phase and applies supplied flash/redout/blackout state. HUDCOL is written directly to the green component of palette index 6, not used as a palette-index selector; see the corrected configuration notes. The VGA upload retains raw bytes, including the default HUD value 125, until the six-bit DAC masks them.

Colour-index mapping

The native loader at 0xd7954 initialises identity mappings and loads root coltab.dat, identifier 7764422a: 16 rows of 256 byte indices. The viewer shows every row under a selectable palette and reports the exact source-to-output index under the pointer. Rows are not labelled brightness or distance steps without a verified caller association.

This is separate from dat/coltab.dat, a 27-byte identity selector sequence 0..26. Similar basenames do not imply the same layout or role.

The texture investigation independently verifies that textured rasterisation applies its selected index remap before deciding whether to skip transparent colour zero. The existing model/scenery viewers use identity remapping and a selected base palette. This page exposes the native tables and environment bindings without claiming to reproduce all live lighting, fog or time-of-day selection. Recovered Gouraud attributes and controlled raster paths are described below.

Seven .sta tables contain 250 tag-word / 5×5-tag-pattern records, using the same vocabulary as ASC authoring metadata. The likely terrain-editor stamp role, diagnostic previews and remaining native-reader questions are documented in the investigation.

Native special raster modes

The viewer now includes 27 controlled native quad/circle captures, generated by capture_raster_modes.py through the original scan converters and a planar VGA harness. raster-modes.json preserves pixel hashes, coverage, callback addresses, logical operations, pattern phases and procedural seeds. The captures can be recoloured with any extracted palette.

Mode Operation
0 Alternating checkerboard pixels
1 Quarter-density staggered dots
2 / 3 Sparse dots with span-dependent phase
4 Procedural stipple with persistent 16-bit seed
7 Horizontal stripes
10 / 11 / 12 XOR / AND / OR of source and destination palette indices

Modes 2/3 count VGA bytes rather than clipping every individual plane at a circle edge; a last dot can lie slightly outside the nominal span. Mode 4 has its own self-modifying seed at 0xe3a3f, independent of model vertex jitter. Its ADD CH,CL / ADC CL,CH sequence advances once per VGA span byte, including edge groups. Original integer circle tables, not a real-valued square root, define the small-radius spans. The model and actor viewers retain a separate procedural seed across draws; disabling Animate effects in the model viewer supplies a fixed inspection seed.

The software model and assembled-object previews support these modes. The model raster matches complete controlled circle rasters for all nine modes, including procedural seed transitions. Across circles and two quad placements it also matches 43,200 interior pixels. This check deliberately distinguishes native callback behaviour from the browser's general half-open polygon edges and clipping. The WebGL scenery preview does not yet implement all these special modes.

Gouraud palette indices

Model opcodes 76/78 contain three/four packed colour bytes; 77/79 draw the shaded triangle/quad. The load conversion preserves those bytes. The native setup handlers at 0xbc498 and 0xbc4b8 store them as 8.8 palette values. The previous viewer ignored these attributes and painted the current flat colour.

The model, cockpit and scenery viewers now carry vertex shade indices. Interpolation selects discrete palette entries; it never blends two RGB colours. The software path retains the tested integer reciprocal and half-step behaviour, while the WebGL scenery path interpolates the palette index and samples a discrete palette texture. Native lighting/remap selection is still separate from this per-polygon interpolation.

capture_shading.py checks 46 packed-attribute cases and eight original Gouraud quads under identity and reversed remaps. check_gouraud.js compares 1,280 native ramp samples. Source pixels and hashes remain in gouraud-checks.json.