Tier-1 FIRST GEOMETRY RENDER: real captured IGC packets -> shaded z-buffered 3D

render_wide30.py executes the cap7 death-cam capture's raw instruction
packets ({TREEgeZERO_L3 x3 edges, MEMltTREE_L3 z-test, TREEintoMEM_L0
z-write, colour planes, scalar} -- 152 packets found by header scan) through
the named-ISA semantics, vectorized: 85 packets survive edge+z, producing a
recognizable smooth-shaded, depth-correct render of the test-scene object
(wide30_render/depth.png in the session scratchpad). This is geometry drawn
purely by executing the hardware's own instruction stream -- no
geometry-extraction shortcuts.

Known approximations this pass: winding-agnostic edge acceptance, colour
plane word-offsets partly empirical (R channel confirmed Gouraud-correct,
G/B extraction still off), duplicate packets from the wide capture window
z-fight. eof/bars ops still stubbed (per-tile program renders uniform).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-18 00:42:52 -05:00
co-authored by Claude Opus 4.8
parent ddaa63f9b0
commit 7bac137a63
2 changed files with 118 additions and 0 deletions
@@ -211,6 +211,24 @@ the eof-block ops 0xfa/0x7c/0x1f/0xf2/0x97/0x05/0x49/0x30/0x75/0xdb (builder =
one linear fn 0xf041ee30-0xf041f7b0, per-word pcs logged in builder_trace2.log —
disasm each site to name them).
## FRAME PIPELINE STATUS (2026-07-18 early)
frame_render.py (scratchpad) executes a send-captured frame end-to-end:
cap7 draw#1 = 52 tiles (13x4 ✓ for 832x512; tile-id origin = (id&0x1f)*64,
(id>>5&0x1f)*128 ✓), 5 distinct payloads (4/16/33/41/69 words) broadcast to all
tiles. Output with 11 ops stubbed = uniform navy (constant from SCAintoMEM in
the eof planes) — structurally sound, pattern generators missing.
**ARCHITECTURE FINDING:** fxtest's animation frame ALSO sends only 4 distinct
payloads — the per-tile IGC program is FIXED; scene content flows through the
TEXTURE path (TXDN per tile + texu/texv computed per-pixel by the 69-block
transform + ramp/mode bits). The wire 'set_texmap_texels' payloads for cap7 are
FLOAT blocks (vertex/normal-like: the action-25 geometry sub-protocol), not
texel arrays — the bar colours are NOT a simple texel table; they come through
the ramp/eof machinery (the stubbed ops). NEXT: name the 11 stubbed ops from the
builder disasm (writer pcs in builder_trace2.log, builder = 0xf041ee30-f7b0
straight-line) + implement the texture/ramp lookup; then bars.
## NEXT (the miner)
Write `eofs_mine.py`: parse EOF.S per function; track `st.l`/`fst.l` stores
through the coeff pointer; recover, in order, each emitted word (int literals
+100
View File
@@ -0,0 +1,100 @@
"""Render the cap7 test-scene from cap7_wide30.pkl's REAL captured IGC packets.
Packets = {SETENABS, 3x TREEgeZERO_L3 edges, MEMltTREE_L3 z-test, TREEintoMEM_L0
z-write, 3x color-plane instrs, scalar}. Executed vectorized (numpy) on a full
832x512 surface with a persistent 1/w z-buffer (MEMltTREE: keep where old < new
=> greater 1/w wins = closer wins)."""
import sys, pickle, struct
import numpy as np
S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad'
W, H = 832, 512
d = pickle.load(open(S + r'\cap7_wide30.pkl', 'rb'))
mem = d['mem']
def f32(w):
return struct.unpack('<f', struct.pack('<I', w & 0xffffffff))[0]
starts = sorted(a for a, w in mem.items() if w == 0x3ae80d00)
# packet head = SETENABS right before the first of each edge triple
# group: consecutive geZERO addresses 16 bytes apart form one packet's 3 edges
packets = []
i = 0
while i < len(starts):
a = starts[i]
if i + 2 < len(starts) and starts[i+1] == a + 16 and starts[i+2] == a + 32:
packets.append(a)
i += 3
else:
i += 1
print("%d triangle packets" % len(packets))
def rdf(a):
return f32(mem.get(a, 0))
def rd(a):
return mem.get(a, 0)
yy, xx = np.mgrid[0:H, 0:W].astype(np.float64)
zbuf = np.full((H, W), -1e30)
rgb = np.zeros((H, W, 3))
drawn = 0
for a in packets:
# edges at a, a+16, a+32: {hdr, A, B, C}
en_pos = np.ones((H, W), bool)
en_neg = np.ones((H, W), bool)
for e in range(3):
ea = a + 16 * e
A, B, C = rdf(ea + 4), rdf(ea + 8), rdf(ea + 12)
v = A * xx + B * yy + C
en_pos &= v >= 0
en_neg &= v < 0
en = en_pos | en_neg # winding-agnostic
if not en.any():
continue
# z instr: scan forward from a+48 for the MEMltTREE header (preambles vary)
za = None
for off in range(48, 48 + 44, 4):
if (rd(a + off) & 0xffffff00) == 0x44ea2100:
za = a + off
break
if za is None:
continue
A, B, C = rdf(za + 4), rdf(za + 8), rdf(za + 12)
z = A * xx + B * yy + C
en &= z > zbuf
if not en.any():
continue
zbuf[en] = z[en]
# z-write at a+64 (1 word), colors from a+68: three 5-word groups
# {clmp-hdr, pword, w2, w3, w4} -- empirical: value plane = {B?, A?, C?}
cols = []
ca = za + 20
for c in range(3):
g = ca + 20 * c
hdr = rd(g)
w1, w2, w3, w4 = rd(g + 4), rd(g + 8), rd(g + 12), rd(g + 16)
# try: the plane floats are the last three words {A?, B?, C?}
fA, fB, fC = f32(w2), f32(w3), f32(w4)
cols.append((fA, fB, fC))
for c, (fA, fB, fC) in enumerate(cols):
plane = fA * xx + fB * yy + fC
rgb[..., c][en] = np.clip(plane[en], 0, 255)
drawn += 1
print("drawn: %d packets" % drawn)
print("rgb range:", rgb.min(), rgb.max())
# normalize for viewing if the scale is off
mx = rgb.max() or 1.0
img = (np.clip(rgb / (mx if mx > 255 else 255), 0, 1) * 255).astype(np.uint8)
from PIL import Image
Image.fromarray(img, 'RGB').save(S + r'\wide30_render.png')
# also a z-buffer visualization (structure check independent of colors)
zv = zbuf.copy()
m = zv > -1e29
if m.any():
zn = (zv - zv[m].min()) / max(1e-9, (zv[m].max() - zv[m].min()))
zi = np.zeros((H, W), np.uint8)
zi[m] = (40 + 215 * zn[m]).astype(np.uint8)
Image.fromarray(zi, 'L').save(S + r'\wide30_depth.png')
print("wrote wide30_render.png + wide30_depth.png")