diff --git a/emulator/firmware-decomp/gridsurf.py b/emulator/firmware-decomp/gridsurf.py new file mode 100644 index 0000000..98859bb --- /dev/null +++ b/emulator/firmware-decomp/gridsurf.py @@ -0,0 +1,95 @@ +"""The captured object is a complete 9x5 height-field grid (verified: all 45 cells +filled, x in {0..16 step 2}, z in {0..-8 step 2}, y = height). Reconstruct the FULL +grid connectivity (2 tris per quad) and render a clean solid surface from a chosen +3/4 view, Gouraud-lit by the captured normals. Real data; only the camera is ours.""" +import sys, pickle, math, json +S = r'C:\Users\cyd\AppData\Local\Temp\claude\c--VWE-TeslaRel410\4e848c76-6e89-4034-8047-d8d491cb32d8\scratchpad' +objs = pickle.load(open(S + r'\vfull.pkl', 'rb'))['objs'] +YAW = float(sys.argv[1]) if len(sys.argv) > 1 else 40.0 +PITCH = float(sys.argv[2]) if len(sys.argv) > 2 else 28.0 +OUT = sys.argv[3] if len(sys.argv) > 3 else 'gridsurf' + +allv = [v for o in objs for v in o] +xs = sorted(set(round(v['mx'], 2) for v in allv)) +zs = sorted(set(round(v['mz'], 2) for v in allv)) +grid = {(round(v['mx'], 2), round(v['mz'], 2)): v for v in allv} +cx = sum(xs)/len(xs); cz = sum(zs)/len(zs) +cy = sum(v['my'] for v in allv)/len(allv) + +ry = math.radians(YAW); rp = math.radians(PITCH) +cyw, syw = math.cos(ry), math.sin(ry); cp, sp = math.cos(rp), math.sin(rp) +def rot(x, y, z): + x, z = x*cyw + z*syw, -x*syw + z*cyw + y, z = y*cp - z*sp, y*sp + z*cp + return x, y, z +def _n(a, b, c): + m = math.sqrt(a*a+b*b+c*c) or 1.0 + return a/m, b/m, c/m +LIGHT = _n(0.35, 0.55, 0.72) + +# rotate every grid vertex + normal, cache projected + intensity +P = {} +for (x, z), v in grid.items(): + X, Y, Z = rot(v['mx']-cx, (v['my']-cy)*1.8, v['mz']-cz) # exaggerate height 1.8x for relief + nx, ny, nz = rot(v['nx'], v['ny'], v['nz']) + n = _n(nx, ny, nz) + d = n[0]*LIGHT[0] + n[1]*LIGHT[1] + n[2]*LIGHT[2] + inten = max(0.16, min(1.0, 0.22 + 0.85*abs(d))) + P[(x, z)] = [X, Y, Z, inten] + +allp = list(P.values()) +mnx = min(p[0] for p in allp); mxx = max(p[0] for p in allp) +mny = min(p[1] for p in allp); mxy = max(p[1] for p in allp) +spanx = (mxx-mnx) or 1; spany = (mxy-mny) or 1 +IW, IH = 620, 560 +PADf = 0.1 +sc = min(IW*(1-2*PADf)/spanx, IH*(1-2*PADf)/spany) +oxp = (IW - spanx*sc)/2; oyp = (IH - spany*sc)/2 +def SX(p): return int((p[0]-mnx)*sc + oxp) +def SY(p): return int((mxy-p[1])*sc + oyp) # flip Y (model up -> screen up) + +fb = [[0.0]*IW for _ in range(IH)] +zb = [[-1e9]*IW for _ in range(IH)] +def tri(a, b, c): + ax, ay, bx, by, cx2, cy2 = SX(a), SY(a), SX(b), SY(b), SX(c), SY(c) + ia, ib, ic = a[3], b[3], c[3]; za, zbv, zc = a[2], b[2], c[2] + area = (bx-ax)*(cy2-ay) - (cx2-ax)*(by-ay) + if abs(area) < 1e-6: return + x0 = max(0, min(ax, bx, cx2)); x1 = min(IW-1, max(ax, bx, cx2)) + y0 = max(0, min(ay, by, cy2)); y1 = min(IH-1, max(ay, by, cy2)) + for py in range(y0, y1+1): + for px in range(x0, x1+1): + w0 = ((bx-px)*(cy2-py) - (cx2-px)*(by-py))/area + w1 = ((cx2-px)*(ay-py) - (ax-px)*(cy2-py))/area + w2 = 1 - w0 - w1 + if w0 < -0.004 or w1 < -0.004 or w2 < -0.004: continue + z = w0*za + w1*zbv + w2*zc + if z > zb[py][px]: + zb[py][px] = z; fb[py][px] = w0*ia + w1*ib + w2*ic + +nt = 0 +for i in range(len(xs)-1): + for j in range(len(zs)-1): + a = P[(xs[i], zs[j])]; b = P[(xs[i+1], zs[j])] + c = P[(xs[i], zs[j+1])]; d = P[(xs[i+1], zs[j+1])] + tri(a, b, c); tri(b, d, c); nt += 2 +print("yaw=%.0f pitch=%.0f grid %dx%d %d tris" % (YAW, PITCH, len(xs), len(zs), nt)) + +ramp = " .:-=+*#%@" +for ry2 in range(0, IH, IH//38): + line = " " + for rx in range(0, IW, IW//74): + v = fb[ry2][rx]; line += ramp[min(9, int(v*9.99))] if v > 0 else ' ' + print(line) + +img = bytearray(IW*IH*3) +for y in range(IH): + for x in range(IW): + v = fb[y][x] + if v > 0: + r = int(min(255, 28+v*168)); g = int(min(255, 50+v*205)); b = int(min(255, 54+v*122)) + else: + r, g, b = 7, 11, 17 + o = (y*IW+x)*3; img[o], img[o+1], img[o+2] = r, g, b +open(S + '\\' + OUT + '.ppm', 'wb').write(b'P6\n%d %d\n255\n' % (IW, IH) + bytes(img)) +print("wrote %s.ppm (%dx%d)" % (OUT, IW, IH)) diff --git a/emulator/firmware-decomp/render-readout.html b/emulator/firmware-decomp/render-readout.html index de339e9..fb8faa2 100644 --- a/emulator/firmware-decomp/render-readout.html +++ b/emulator/firmware-decomp/render-readout.html @@ -44,6 +44,15 @@ font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;color:var(--mute); text-transform:uppercase;line-height:1.5} .hero-render .cap b{color:var(--phos)} + .duo{display:grid;grid-template-columns:1.5fr 1fr;gap:14px;margin-top:18px} + @media(max-width:640px){.duo{grid-template-columns:1fr}} + .duo figure{margin:0;border:1px solid var(--line2);border-radius:10px;overflow:hidden; + background:radial-gradient(130% 110% at 50% 12%, #0a141c, #05090d)} + .duo canvas{display:block;width:100%;height:auto} + .duo figcaption{padding:10px 13px;font-family:var(--mono);font-size:11px; + letter-spacing:.05em;color:var(--mute);line-height:1.5;border-top:1px solid var(--line)} + .duo figcaption b{color:var(--phos)} + .hero-render .tag{position:absolute;top:12px;left:16px;font-family:var(--mono); font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--faint); border:1px solid var(--line2);border-radius:5px;padding:4px 9px;z-index:2} @@ -152,15 +161,16 @@
A cycle-faithful Intel i860 interpreter now runs the game's actual shipped firmware — booted, initialised, and fed a complete recorded mission over the wire. It replays every command, emits the real - PXPL5 IGC render stream, and projects the scene geometry. Below is the object - it drew, pulled straight off the emulated chip and shaded from its own vertex - normals — the first frame from this board's firmware in thirty years.
+ PXPL5 IGC render stream, and projects the scene geometry. Below is an object + it drew, its vertices and normals pulled straight off the emulated chip and + reconstructed in 3D — geometry this board's firmware has not computed in thirty years.One step upstream of the micro-code, the firmware transforms each model - through its matrix and writes screen-space vertices, organised as - VSTRIP triangle strips. Below is a wireframe reconstructed - live from the emulated i860 — the actual object in cap7's death-camera view, - four strips, 45 vertices, exactly as the board's firmware projected it. This is the - real geometry the Pixel-Planes array was about to shade.
-The surface above is the same 45 vertices, sorted back into model space — + they form an exact 9 × 5 height-field grid (x and z in even 2-unit steps, y the + height at every node; all 45 cells filled). What the board actually wrote to screen is + below: cap7's death-camera views that surface nearly edge-on, so the frame the i860 + projected is a thin, folded sliver. It is authentic output — just an awkward angle. Left, + that projection Gouraud-shaded; right, its raw VSTRIP wireframe.
+