Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / Latest research roundsNeueste Forschungsrunden

Texture Codec 2 Tile Chains: Inner Pixel Layout (Still Unsolved)

OpenOffen Original page in the GitHub wikiOriginalseite im GitHub-Wiki

In plain wordsIn einfachen Worten

Wolfenstein II: The New Colossus stores large normal-map textures in an undocumented format called codec 2. This pass tested four more ideas for how its pixels are arranged, and all four failed against scrambled control tests. The useful new fact is that each tile has a short, busy head followed by a long, nearly flat tail. For modders nothing changes: replacement textures can use the simpler, understood codec 1 format at any size.

  • 9 layout guesses have now been rejected across two research passes, all with control tests.
  • Every tile has a short head of about 3 to 6 percent with more varied data, then a long flat tail.
  • The tail's most common byte is 0x7F in all 16 checked tiles, the neutral value for a normal map.
  • All four code spots that read the codec value only do bookkeeping; none decodes pixels.
  • Workaround stays valid: ship replacement textures as codec 1.

Wolfenstein II: The New Colossus speichert große Normal-Map-Texturen in einem undokumentierten Format namens Codec 2. Dieser Durchgang testete vier weitere Ideen, wie die Pixel darin angeordnet sind, und alle vier scheiterten an verwürfelten Kontrolltests. Die nützliche neue Erkenntnis: Jede Kachel hat einen kurzen, unruhigen Kopf und danach einen langen, fast flachen Schwanz. Für Modder ändert sich nichts: Ersatztexturen können das einfachere, verstandene Codec-1-Format in jeder Größe nutzen.

  • 9 Layout-Vermutungen sind inzwischen über zwei Forschungsdurchgänge verworfen, alle mit Kontrolltests.
  • Jede Kachel hat einen kurzen Kopf von etwa 3 bis 6 Prozent mit vielfältigeren Daten, danach einen langen flachen Schwanz.
  • Das häufigste Byte im Schwanz ist in allen 16 geprüften Kacheln 0x7F, der neutrale Wert für eine Normal-Map.
  • Alle vier Codestellen, die den Codec-Wert lesen, machen nur Verwaltung; keine dekodiert Pixel.
  • Der Workaround bleibt gültig: Ersatztexturen als Codec 1 ausliefern.

Technical detailsTechnische Details

Der technische Teil ist auf Englisch – so, wie er im Wiki steht. Unterstrichene Begriffe haben eine Erklärung auf Deutsch.

TNC stores large normal-map mips using an undocumented "codec 2" tile-chain format whose inner pixel layout earlier research could not decode, having already ruled out raw planes, simple raster BC4/BC5 blocks, and a GPU-dispatcher explanation. This pass tested four more concrete layout hypotheses — two BC5-specific geometric splits, a BC4 bit-plane split, and "the high-entropy region is just top-anchored raster data" — and every one was rejected using the same derangement-plus-correlation negative-control discipline as earlier work. The most useful new result is structural, not a solved layout: every codec-2 tile has a short, higher-entropy "head" region followed by a long, nearly flat "tail" dominated by a single constant byte, a real and reproducible pattern that no tested hypothesis explains yet. This is pure static byte-level and disassembly research with no game launch; the practical modding workaround (write replacement textures using the simpler, understood "codec 1" format at any size) is unaffected either way.

What was ruled out this round

All four tested with real negative controls (a scrambled/derangement version of each hypothesis, which should score the same as the real hypothesis if the hypothesis is wrong — and did, every time):

  • BC5 as two GPU-hardware-standard sparse tiles placed side by side (a genuinely new geometric idea, distinct from the already-rejected whole-tile raster reading).
  • BC5 stored as two separate channel planes (all X-channel blocks, then all Y-channel blocks) instead of the normal interleaved format.
  • BC4 stored as a structure-of-arrays split (all endpoint pairs, then all index data) instead of interleaved per block.
  • The short high-entropy "head" region read as plain top-anchored raster BC4.

This brings the running total to 9 rejected pixel-layout/mechanism hypotheses across two research passes, all tested the same rigorous way.

The real structural finding

A byte-statistics scan (independent of any pixel-decoding assumption) shows every codec-2 tile has two clearly distinct regions: a short "head" (roughly the first 3–6% of the buffer, varying per tile rather than sitting at a fixed offset) at meaningfully higher entropy, followed by a long, nearly flat "tail" at very low entropy. The tail's single most common byte value is 0x7F in every one of 16 spot-checked tiles (42–95% share) — the tangent-space-neutral value for a normal-map channel, consistent with (not proof of) genuine but heavily redundant normal-map content. A follow-up test found a real but modest statistical link between how long the head region is and how much real visual detail the corresponding reference image has (weak positive correlation, stronger for BC5 than BC4) — consistent with a content-driven, variable-length payload rather than a fixed container field, though the effect is too small to use as a hard layout boundary by itself.

Two more candidate explanations for the head region were tested and rejected: it is not a second, nested compressed stream (a random-byte control "detected" a fake compressed stream more often than the real head bytes did), and it does not correspond to id Software's older, now-abandoned virtual-texture ("MegaTexture") format — an independent check of public community documentation confirmed TNC specifically dropped that older system in favor of the simpler streaming format this project already fully understands (unlike a contemporaneous sibling game on the same engine generation, which kept it) — a genuine engineering difference between the two games, not a property of the shared engine family.

Engine code trace

Disassembly of every place in the executable that reads the per-tile "codec" byte (four sites total now, up from two in earlier work) found every one of them to be bookkeeping — a logging/telemetry call, a lock-free queue push, and a flat struct copy forwarding the tile's metadata into what looks like a render-thread command buffer. None of the four branches on the codec value to do anything pixel-shaped. One newly found site (a large, only partially examined function that forwards the tile record toward a render-backend command buffer) is the single most promising remaining lead for static analysis, but has not yet been walked to its actual consumer.

For modders

Nothing changes the practical recommendation from earlier work: ship replacement textures/mips using the simpler, already-understood "codec 1" format, which the engine accepts at any size — codec 2 itself still has no known encoder and isn't needed for ordinary texture replacement.

Open questions

  • What the head region actually contains.
  • Whether the tail's near-constant content is genuine (if redundant) texture data or allocation padding — one cheap, still-untested check: compare tail bytes byte-for-byte across two unrelated, genuinely flat textures.
  • Where the render-command buffer found this pass is ultimately consumed, and whether that code ever branches on the codec byte.
  • A GPU-level trace (e.g. with a graphics debugger during an actual texture upload) remains the only lead that isn't more static guesswork, and was out of scope for this read-only track.