Explain the tie texcoord residual: i16[3] selects the encoding

The texcoords are 12-bit fixed on 82.5% of vertices, not 100%, and the residual
had no explanation. Grouped by the vertex's i16[3] slot across 95,612 vertices on
levels 0-2, the buckets separate completely:

  i16[3]          n        % / 4096      % / 256
  negative        333        1.2%          1.2%
  == 0          5,851       29.2%         60.7%
  1..63        28,884       92.7%         94.3%
  64..255      54,606       92.3%         93.8%
  256..511          8        0.0%          0.0%
  512..1023      5,391        0.0%          0.0%
  >= 1024         539        0.2%          0.2%

The residual is fully accounted for. 87.3% of vertices sit in 1..255 at about 92.5%
fixedness, contributing 0.873 * 0.925 = 80.8 points; the 5,851 at i16[3] == 0
contribute 1.8 more. That is the 82.5% measured, to the point.

The remaining ~6% are not 12-bit fixed at all. i16[3] >= 256, and negatives, score
0% at BOTH 4096 and 256 -- 6,271 vertices in an encoding this reading does not
see. And i16[3] == 0 scores 29.2% at 4096 but 60.7% at 256, which is a third
distribution rather than a weaker version of the same one.

What this establishes: i16[3] is a per-vertex packed attribute whose value SELECTS
HOW the texcoord pair is stored, rather than an independent field sitting beside
the texcoords. 1-255 is the ordinary case, 0 is special, 256-and-up and negatives
are a different encoding. What those three cases MEAN is still open -- texture
index, normal index, flag or a combination -- but it is now a field whose role is
known, which is more than "packed word".

Worth noting the shape of the claim this replaces: "the texcoords are 12-bit fixed
at i16[4]/i16[5], 73.6% of the time, unexplained". The field position was right;
the 73.6% was a population average over three encodings. Partitioning by the one
variable that separates them turns a mystery into a lookup -- rule 3a again, and the
third time this session that partitioning a mystery produced the answer rather than
merely bounding it.
This commit is contained in:
2026-10-13 05:19:06 +02:00
parent 3ee0b3d0dc
commit e27c40e738
2 changed files with 51 additions and 6 deletions
+10 -6
View File
@@ -293,13 +293,17 @@ Phase 1 hands over the extents; this phase works out what each one contains.
against 1.1% for `(0,1)` and 4.8% for `(2,3)`. The `(6,7)` pair scores
*higher* at 76.6% and is **not** a texcoord -- it is the near-constant
`4096, 0` pair, which is trivially two multiples of 4,096.
- [x] `i16[3]` **selects the texcoord encoding**, which explains the residual.
Grouped across 95,612 vertices on levels 0-2: `1..63` and `64..255` score
92.7% and 92.3% 12-bit fixed, `== 0` scores 29.2% at 4,096 but **60.7% at
256** -- a third distribution -- and everything at 256 or above, or
negative, scores **0%** at both. The 87.3% of vertices in `1..255`
contribute exactly the 82.5% measured overall, so the residual is fully
accounted for. It is a field whose *role* is known even though its meaning
is not.
- [ ] The remaining tie vertex **fields are not named.** `i16[0..3]` span the full
`i16` range with 10,803-13,421 distinct values each, so they are neither
texcoords nor small fields; they are most likely position plus a packed
word, but that is not established. The texcoord rate is 73.6% rather than
100% and the vertex base is confirmed to be `vert_ofs` alone (adding the
shader or control region makes it worse), so the residual is not a
mislocated base.
`i16` range with 10,803-13,421 distinct values each. `i16[0..2]` are most
likely position, but that is not established.
- [~] `shrub` — class table done (48-byte entries, not 32; reading shrub at
32 still gives 231 sane-looking entries of 358, which is the hazard).
Geometry header parsed and checked field by field on all 358 spans: