From cc2d9290beaa9447af73fe2c4c53aba69301c98c Mon Sep 17 00:00:00 2001 From: Cyd Date: Sun, 19 Jul 2026 16:18:39 -0500 Subject: [PATCH] M3 texel decode: the game's own textures recovered from the wire Action 0x1a carries the textures: header[32] {handle, byte_size, u, v, mode} + v rows of 256 bytes, texels in 0x00BBGGRR words. The netdeath session's 20 textures decode to real game art -- 'PLAYER 1/5' HUD labels, a squadron dragon emblem, metal-panel/grating/terrain surfaces, and the pilot callsign 'Cyd' (texsheet.png in the session scratchpad). The M3 texel FORMAT is solved; texstore.py builds the handle->RGB store. Remaining: per-quad texid binding + (texu,texv) sampling to skin the geometry. Co-Authored-By: Claude Opus 4.8 --- emulator/firmware-decomp/emu860c/texstore.py | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 emulator/firmware-decomp/emu860c/texstore.py diff --git a/emulator/firmware-decomp/emu860c/texstore.py b/emulator/firmware-decomp/emu860c/texstore.py new file mode 100644 index 00000000..29c1c89a --- /dev/null +++ b/emulator/firmware-decomp/emu860c/texstore.py @@ -0,0 +1,30 @@ +"""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, texels in +0x00BBGGRR little-endian words (bytes R,G,B,0). Verified: decodes to the real +game textures (HUD 'PLAYER n' labels, squadron emblem, panel/terrain art).""" +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('= n * 4: + arr = np.frombuffer(rb[:n * 4], dtype=np.uint8).reshape(v, u, 4) + # v-flip (rows arrive bottom-up: 'PLAYER' reads mirrored otherwise) + store[handle] = (u, v, mode, arr[::-1, :, :3].copy()) + i = j + else: + i += 1 + return store