# Texture pages and model bindings

The [texture browser](textures/index.html) shows indexed atlas artwork and each referring model's UV outlines. Textures are also drawn in the [model](models/index.html), [assembled-definition](objects/index.html) and [map](maps/index.html) viewers. Model OBJ exports include `vt` coordinates; MTL files refer to the palette-coloured PNG downloads beside them. The map's OBJ export remains a geometry export.

## Native page layout

A `.tm` contains **49,152 bytes: 256 columns × 192 rows**, with no header or palette. Its texel address is `V * 256 + U`. Unlike sprite banks and `.256` animations, these pixels are not four contiguous VGA planes. Each byte is a palette index; the environment supplies the current colours.

The global loader at [file 0xc7588](code/index.html#c7588) requests `global_1.tm` through `global_8.tm` and stores their handles in the code object's table at offset `0x47c84`. The reference archive supplies only the first four:

| Model slot | Resource | Identifier | Observed artwork |
| ---: | --- | --- | --- |
| 0 | `spr/global_1.tm` | `a5d5d4e5` | Blast scars, smoke/chaff, sun/flare artwork and part of the instrument panel |
| 1 | `spr/global_2.tm` | `a6d7d2e5` | Cockpit panel, instrument screens and aircraft markings |
| 2 | `spr/global_3.tm` | `a7d9d0e5` | Additional aircraft artwork |
| 3 | `spr/global_4.tm` | `a8dbdee5` | Predominantly index-191 surface artwork |

There are **12 page-sized resources** in total, including regional map pages, `gamespr.tm`, three pages whose names remain unidentified, and the four globals. Blank or unused page regions are retained. The separate `global_1.tmt` resource has a 768-byte palette and 64,000-byte image payload; it is not the raw page loaded by this renderer. Its relationship to the `.tm` conversion still needs verification.

## Shape instructions

Opcode **71** chooses a global slot and supplies one UV pair per corner. The native converter at `0xba423` doubles the slot number to address its handle word, and shifts each UV coordinate left by seven bits. The drawing handler at [0xbc380](code/index.html#bc380) resolves that handle and copies the UV pairs into the renderer's attribute buffer.

Opcode **46** uses a model's cached texture handle instead. When the model's cache fields at bytes 48/52 are both zero, the converter calls [0xc7424](code/index.html#c7424). The NUL-terminated name at byte 56 is its binding: a leading `!` selects a raw `.tm` page, otherwise the loader looks for a `.spr` bank. The three named bindings recovered here all use **`!GAMESPR`**. Other opcode-46 models rely on runtime bindings; the browser keeps those unresolved rather than assigning an unrelated atlas.

Opcode **47** draws the textured polygon through [0xbdc38](code/index.html#bdc38). **Opcode 50 is a shaded polygon, not a texture draw**: it dispatches through `0xbd95c` and uses the shade-attribute buffer rather than UVs. The earlier placeholder treatment incorrectly grouped those two instructions together.

`tripipe`'s damaged state selects slot 0 and UV corners `(161,76)`, `(217,76)`, `(217,136)`, `(161,136)`. This is the radial blast scar in `global_1.tm`. Transparent surrounding texels now reveal the scenery underneath rather than filling the entire ground quad grey.

## Sampling and transparency

The native scanline routine at [0xe5dd8](code/index.html#e5dd8) interpolates UVs **affinely in screen space**. It fetches an indexed texel, remaps it through the current lighting table, then skips the write if the resulting index is zero. Thus transparency is tested **after** remapping. A raw zero can become visible if mapped to a nonzero index; a nonzero raw index mapped to zero disappears.

The inspection viewers use an identity lighting remap and the chosen base palette. They sample nearest texels and preserve discrete palette indices. Their zero-index texels consequently leave the destination untouched. The WebGL map path also preserves affine UV interpolation. These are artwork previews; native lighting, fog and pixel-exact integer scan conversion are not claimed.

[check_textures.py](../tools/check_textures.py) runs the original textured-polygon, edge and scanline routines with reconstructed VGA planes. [Native captures](textures/native-checks.json) cover **96 samples across all 12 pages**, including last-row/last-column UVs, two post-lookup transparency cases and a quad with changing U/V. This verifies page dimensions, axis orientation, addressing and the transparency decision independently of the browser implementation.
