Skip to content

Commit 0a1b6f2

Browse files
LinuxJessiclaude
andcommitted
Texture decode: run the raw-CT32 pass only for model-bound textures
Verifying issue #1 against v1.0.0 turned up a regression from the Aug 21 decoder: the raw-CT32 pass also fired on lex-less UI sheets, where dithered 8bpp art (two indices alternating) reads as a coherent checker when taken as CT32. The casino slot reels (tanaka/slot_1) came out blue/yellow checkered and the poker felt (tanaka/poker_1) half garbled. The pass now runs only when a .lex exists. Verified through the real browse pipeline: all 114 char/pc + char/npc atlases byte-identical to before (hair-sheet fixes intact); slot reels and poker felt clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent c03baef commit 0a1b6f2

3 files changed

Lines changed: 25 additions & 2 deletions

File tree

‎browse.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,12 @@ def paint(pal, u0, u1, v0, v1):
620620
# block on the KOS-MOS atlas measures below that) but the canvas read
621621
# directly as CT32 is more coherent, draw the block from the canvas —
622622
# each canvas pixel covers 2x2 output pixels.
623-
for v0 in range(0, H, 64):
623+
# Only for model-bound textures (a .lex exists): true-colour regions are
624+
# a character-model feature, and on the lex-less UI sheets the pass
625+
# mis-fired on dithered 8bpp art — the casino slot reels (two indices
626+
# alternating) read as a "coherent" checker when taken as CT32 and were
627+
# repainted blue/yellow (regression vs the July build, found 2026-09-24).
628+
for v0 in (range(0, H, 64) if lexes else ()):
624629
v1 = min(H, v0 + 64)
625630
for u0 in range(0, W, 64):
626631
u1 = min(W, u0 + 64)

‎docs/FORMATS.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,11 @@ still measures as dither noise (`_rgba_noise` ratio >= 0.9; correctly
185185
paletted blocks measure below that) and the canvas region read directly
186186
as CT32 is more coherent, the block is drawn straight from the canvas
187187
(each canvas pixel = 2x2 output pixels, alpha scaled 7->8 bit). This
188-
finally renders the KOS-MOS hair band as hair instead of noise.
188+
finally renders the KOS-MOS hair band as hair instead of noise. The pass
189+
runs only when the texture has a `.lex` (true-colour regions are a
190+
model feature): on lex-less UI sheets it mis-fired on dithered 8bpp art
191+
(two indices alternating reads as a coherent checker in CT32) and
192+
repainted the casino slot reels — regression found 2026-09-24.
189193
Regions failing both readings stay garbled — the remaining static limit.
190194

191195
## Scene archives `.a` (+ `.fpk`, `.arc`) — ARX-packed members (`browse.py: iter_arx_containers`)

‎docs/UPDATES.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ compressed stream, while its pixels do not exist until decompression.
3737
is the ARX bit stream (the entry-level sweep works because the hair
3838
words are stream literals).
3939

40+
### Casino regression fixed (raw-CT32 pass gated)
41+
42+
Verifying issue #1 against the July build turned up a regression from
43+
the 2026-08-21 decoder: the raw-CT32 pass (which draws true-colour
44+
hair sheets straight from the canvas) also fired on lex-less UI sheets,
45+
where dithered 8bpp art — two indices alternating — reads as a
46+
"coherent" checker when taken as CT32. The casino slot reels
47+
(`tanaka/slot_1`) came out blue/yellow checkered and the poker felt
48+
(`tanaka/poker_1`) half garbled. The pass now runs only for model-bound
49+
textures (a `.lex` exists); verified byte-identical output on all 114
50+
`char/pc` + `char/npc` atlases, clean reels and felt. Still imperfect in
51+
the casino: `base.png` (slot symbol sheet) is tinted by a wrong overlay
52+
palette, as it was in every build.
53+
4054
To pick this up: re-run `browse --kinds textures` on an existing dump
4155
(no re-extract). Pure-Python ARX adds ~2 minutes to the sweep.
4256

0 commit comments

Comments
 (0)