Files
TeslaRel410/emulator/firmware-decomp/emu860c/texstore.py
T
CydandClaude Opus 4.8 bf234842cb Commit the texel-format fix + shared dpl_sampler module (was uncommitted)
These changes were made and verified earlier this session (the all-cyan bug
fix is already recorded as SOLVED in project memory) but never got committed --
render_final.py has referenced dpl_sampler as a module in its docstring since
ac4142e7, yet dpl_sampler.py itself was never added, leaving the repo unable
to run the M4b/M4c/M4d renderer scripts that all import it.

texstore.py: fix the texel word format. SVT texels are [pad,B,G,R] (ground
truth: dpl3-revive patha/vrboard.py do_texels + stage_assets.py); reading RGB
as bytes (0,1,2)=(pad,B,G) zeroed red, producing the all-cyan render. Correct
read is bytes (3,2,1).

dpl_sampler.py: the authentic IG-board texture-value model (wrap repeat/clamp,
near-black CUT keying) factored into its own tested module, distilled from the
shipped libDPL headers -- see IG-SHADING-MODEL.md (also added, referenced by
render_final.py's docstring but likewise never committed).

igc_exec.py: OP48/OP49 candidate opcodes (pixel global-X/Y seed into mem) added
to the CPU golden-model executor alongside the existing SCMEMA seed handling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 10:07:16 -05:00

41 lines
1.8 KiB
Python

"""M3 texel store: parse the game wire's action-0x1a texture uploads into a
handle -> (u_size, v_size, mode, RGB array) dict. Format: header[32] =
{handle, byte_size, u, v, mode, ...}, then v rows of 256 bytes, then n=u*v texels.
TEXEL WORD = [pad, B, G, R] bytes -- "SVT xbgr" (ground truth: dpl3-revive
patha/vrboard.py:448 `do_texels` + stage_assets.py:43, the actual renderer's own
decode). Byte 0 is a PAD (verified: 0 in every texel across the capture); the
colour is bytes 1,2,3 = B,G,R, so RGB = bytes (3,2,1). There is NO alpha byte --
cutout ("dpl_tex_value_cut") is done by NEAR-BLACK keying at draw time, not a
stored channel (patha/vrview_gl.py). `mode` 1 is the board's internal 8-bit
storage path; the WIRE upload is always 4 bytes/texel regardless of mode.
Reading RGB as bytes (0,1,2) = (pad,B,G) -- zero red -- was the all-CYAN bug."""
import struct
import numpy as np
def build_texstore(recs):
store = {}
i = 0
while i < len(recs):
a, p = recs[i]
if a == 0x1a and len(p) == 32:
h = [struct.unpack_from('<I', p, 4 * k)[0] for k in range(8)]
handle, u, v, mode = h[0], h[2], h[3], h[4]
rb = b''
j = i + 1
while j < len(recs) and recs[j][0] == 0x1a and len(recs[j][1]) == 256:
rb += bytes(recs[j][1]); j += 1
n = u * v
if n and len(rb) >= n * 4:
arr = np.frombuffer(rb[:n * 4], dtype=np.uint8).reshape(v, u, 4)
# texel = [pad,B,G,R] -> RGB = bytes (3,2,1); v-flip (rows arrive
# bottom-up: 'PLAYER' reads mirrored otherwise)
rgb = arr[::-1, :, 3:0:-1].copy() # (R,G,B) from (3,2,1)
store[handle] = (u, v, mode, rgb)
i = j
else:
i += 1
return store