code wiki / _hdl_build / nx_vrframe.nx

nx_vrframe.nx source

↩ module page · 238 lines · 10697 B

1// nx_vrframe.nx -- F1106 VR-RUNTIME RUNG 1: the SOVEREIGN VR COMPOSITOR FRAME (operator 2026-08-10: 2// "do you know how to actually build a vr hot and virtamate" -> the one honest GAP is the headset 3// runtime; stereo already exists 4/4). This organ produces the SUBMIT-READY frame a VR compositor 4// hands to a headset: two eye views with horizontal parallax (off-axis pinhole per eye) THROUGH the 5// OpenXR-standard radial LENS PRE-DISTORTION (barrel warp r' = r*(1+k1*r^2+k2*r^4)), so the pincushion 6// lens un-warps it to rectilinear -- the characteristic rounded VR frame with black corners. 7// NEVER-BRICK BY CONSTRUCTION (Rule 26): pure compute + ONE regular-file PNG write. It touches NO 8// device/firmware/CMOS/vBIOS namespace -- there is no code path here that can write persistent hardware 9// state, and the gate proves the output sink is a regular knowledge/sites path, never /dev|/sys|/proc. 10// Scene is a deterministic 3D depth test (receding checker floor + depth-sorted pillars) chosen because 11// stereo/lens correctness is what rung 1 proves; the SUBJECT (a VaM-class figure) composes later off the 12// certified body lane. Emits knowledge/nx_vrframe.png (1024x512 L|R) + sites/nishifamily/world/vrframe.png. 13// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 14import "nx_syscalls.nx" 15import "nx_png.nx" 16const VF_MAGIC_374761393: i64 = 374761393 17const VF_MAGIC_668265263: i64 = 668265263 18const VF_MAGIC_1274126177: i64 = 1274126177 19const VF_MAGIC_1180: i64 = 1180 20const VF_MAGIC_1600: i64 = 1600 21const VF_MAGIC_2100: i64 = 2100 22const VF_MAGIC_2900: i64 = 2900 23 24const VF_EW: i64 = 384 25const VF_EH: i64 = 384 26const VF_FOCAL: i64 = 420 27const VF_CAMY: i64 = 165 // eye height above the floor (world units) 28const VF_IPD: i64 = 62 // half interpupillary offset in world units (per eye, +/-) 29const VF_FX: i64 = 1024 // fixed-point unit for the distortion polynomial 30const VF_K1: i64 = 120 // barrel radial coefficients (pincushion-lens inverse) 31const VF_K2: i64 = 40 32const VF_TILE: i64 = 130 // floor checker tile (world units) 33const VF_65536: i64 = 65536 34 35func vw2(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 36func vn2(v: i64) -> i64 { 37 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 38 var m: i64=v 39 if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 40 let t: *u8=sys_mmap(32); var k: i64=0 41 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 42 let o: *u8=sys_mmap(32); var q: i64=k-1; var i: i64=0 43 while q>=0 { o[i]=t[q]; i=i+1; q=q-1 } 44 sys_write(1,o,i); return 0 45} 46func vf_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 47func vf_pack(r: i64, g: i64, b: i64) -> i64 { 48 return vf_clamp(r,0,255) + vf_clamp(g,0,255)*256 + vf_clamp(b,0,255)*VF_65536 49} 50func vf_hash(a: i64, b: i64) -> i64 { 51 var h: i64 = a*VF_MAGIC_374761393 + b*VF_MAGIC_668265263 52 h = (h ^ (h >> 13)) * VF_MAGIC_1274126177 53 h = h ^ (h >> 16) 54 if h < 0 { h = 0 - h } 55 return h 56} 57 58// pillar table: cx, cz (world), half-width, height, r,g,b -- 6 pillars at varied depth for stereo cue 59func vf_np() -> i64 { return 6 } 60func vf_pill(i: i64, k: i64) -> i64 { 61 let px: *i64 = sys_mmap(vf_np()*7*8) as *i64 62 px[0]=-260; px[1]=520; px[2]=55; px[3]=300; px[4]=196; px[5]=120; px[6]=88 63 px[7]= 240; px[8]=760; px[9]=70; px[10]=430; px[11]=120; px[12]=150; px[13]=196 64 px[14]=-90; px[15]=VF_MAGIC_1180;px[16]=95; px[17]=560; px[18]=210; px[19]=170; px[20]=110 65 px[21]=420; px[22]=VF_MAGIC_1600;px[23]=120;px[24]=700; px[25]=150; px[26]=190; px[27]=140 66 px[28]=-380;px[29]=VF_MAGIC_2100;px[30]=150;px[31]=820; px[32]=170; px[33]=140; px[34]=190 67 px[35]=70; px[36]=VF_MAGIC_2900;px[37]=200;px[38]=980; px[39]=120; px[40]=120; px[41]=130 68 return px[i*7+k] 69} 70 71// render ONE rectilinear eye into out[VF_EW*VF_EH]; eyeX = off-axis eye translation (world units). 72// px = the pillar table (built ONCE by the caller, not re-mmap'd per pixel). 73func vf_render_eye(eyeX: i64, out: *i64, px: *i64) -> i64 { 74 let HW: i64 = VF_EW/2 75 let HH: i64 = VF_EH/2 76 // sky + floor per pixel (floor is projected THROUGH eyeX => real floor parallax) 77 var y: i64 = 0 78 while y < VF_EH { 79 var x: i64 = 0 80 while x < VF_EW { 81 let ndcx: i64 = x - HW 82 let ndcy: i64 = HH - y 83 var col: i64 = 0 84 if ndcy >= 0 { 85 // sky gradient (up = deeper blue) 86 let t: i64 = ndcy*1000/HH 87 col = vf_pack(120 + t/9, 150 + t/12, 205 + t/26) 88 } else { 89 // floor plane y=0, camera at height VF_CAMY, ray (ndcx, ndcy, FOCAL); hits at t=CAMY/(-ndcy) 90 let denom: i64 = 0 - ndcy 91 let wz: i64 = VF_CAMY*VF_FOCAL/denom 92 let wx: i64 = eyeX + VF_CAMY*ndcx/denom 93 var cxk: i64 = wx/VF_TILE 94 if wx < 0 { cxk = cxk - 1 } 95 let czk: i64 = wz/VF_TILE 96 var chk: i64 = (cxk + czk) 97 if chk < 0 { chk = 0 - chk } 98 var base: i64 = 70 99 if chk % 2 == 0 { base = 96 } 100 // distance fog toward the horizon 101 var fog: i64 = wz/9 102 if fog > 150 { fog = 150 } 103 let g0: i64 = vf_hash(cxk, czk) % 17 - 8 104 col = vf_pack(base+fog/2+g0, base+8+fog/2+g0, base-14+fog+g0) 105 } 106 out[y*VF_EW+x] = col 107 x = x + 1 108 } 109 y = y + 1 110 } 111 // pillars painter's-sorted far->near (table is already ascending in cz) 112 var pi: i64 = vf_np() - 1 113 while pi >= 0 { 114 let pcx: i64 = px[pi*7+0] 115 let pcz: i64 = px[pi*7+1] 116 let phw: i64 = px[pi*7+2] 117 let phh: i64 = px[pi*7+3] 118 let pr: i64 = px[pi*7+4] 119 let pg: i64 = px[pi*7+5] 120 let pb: i64 = px[pi*7+6] 121 // project: near pillar (small cz) shifts more with eyeX => stereo disparity 122 let sxc: i64 = HW + (pcx - eyeX)*VF_FOCAL/pcz 123 let sw: i64 = phw*VF_FOCAL/pcz 124 let syb: i64 = HH + VF_CAMY*VF_FOCAL/pcz // base (floor contact) screen y 125 let sh: i64 = phh*VF_FOCAL/pcz 126 let x0: i64 = sxc - sw 127 let x1: i64 = sxc + sw 128 let yt: i64 = syb - sh 129 var yy: i64 = yt 130 while yy < syb { 131 if yy >= 0 { if yy < VF_EH { 132 var xx: i64 = x0 133 while xx < x1 { 134 if xx >= 0 { if xx < VF_EW { 135 // faux 3D: lit left, shaded right third, brick banding 136 var r2: i64 = pr 137 var g2: i64 = pg 138 var b2: i64 = pb 139 if xx > sxc + sw/3 { r2=r2*7/10; g2=g2*7/10; b2=b2*7/10 } 140 if xx < sxc - sw/3 { r2=r2*12/10; g2=g2*12/10; b2=b2*12/10 } 141 let band: i64 = (yy - yt) / 9 142 if (yy - yt) - band*9 == 0 { r2=r2*8/10; g2=g2*8/10; b2=b2*8/10 } 143 let jj: i64 = vf_hash(xx/4, yy/4 + pi*97) % 13 - 6 144 out[yy*VF_EW+xx] = vf_pack(r2+jj, g2+jj, b2+jj) 145 } } 146 xx = xx + 1 147 } 148 } } 149 yy = yy + 1 150 } 151 pi = pi - 1 152 } 153 return 0 154} 155 156// apply OpenXR-standard radial barrel pre-distortion: sample rectilinear src into distorted dst. 157// distort=0 => passthrough (the neg-control path: a flat blit is NOT a VR frame). 158func vf_distort(src: *i64, dst: *i64, distort: i64) -> i64 { 159 let cx: i64 = VF_EW/2 160 let cy: i64 = VF_EH/2 161 var y: i64 = 0 162 while y < VF_EH { 163 var x: i64 = 0 164 while x < VF_EW { 165 if distort == 0 { 166 dst[y*VF_EW+x] = src[y*VF_EW+x] 167 } else { 168 let nx: i64 = x - cx 169 let ny: i64 = y - cy 170 let r2: i64 = nx*nx + ny*ny 171 let rrq: i64 = r2*VF_FX/(cx*cx) 172 let scale: i64 = VF_FX + VF_K1*rrq/VF_FX + VF_K2*rrq/VF_FX*rrq/VF_FX 173 let sx: i64 = cx + nx*scale/VF_FX 174 let sy: i64 = cy + ny*scale/VF_FX 175 var c: i64 = 0 // out-of-bounds => black pincushion border 176 if sx >= 0 { if sx < VF_EW { if sy >= 0 { if sy < VF_EH { 177 c = src[sy*VF_EW+sx] 178 } } } } 179 dst[y*VF_EW+x] = c 180 } 181 x = x + 1 182 } 183 y = y + 1 184 } 185 return 0 186} 187 188func vf_build(distort: i64, outpath: *u8) -> i64 { 189 let npx: i64 = VF_EW*VF_EH 190 let le: *i64 = sys_mmap(npx*8) as *i64 191 let re: *i64 = sys_mmap(npx*8) as *i64 192 let ld: *i64 = sys_mmap(npx*8) as *i64 193 let rd: *i64 = sys_mmap(npx*8) as *i64 194 let px: *i64 = sys_mmap(vf_np()*7*8) as *i64 195 vf_pilltab(px) 196 vf_render_eye(0 - VF_IPD, le, px) 197 vf_render_eye(VF_IPD, re, px) 198 vf_distort(le, ld, distort) 199 vf_distort(re, rd, distort) 200 let W2: i64 = VF_EW*2 201 let combo: *i64 = sys_mmap(W2*VF_EH*8) as *i64 202 var y: i64 = 0 203 while y < VF_EH { 204 var x: i64 = 0 205 while x < VF_EW { 206 combo[y*W2 + x] = ld[y*VF_EW+x] 207 combo[y*W2 + VF_EW + x] = rd[y*VF_EW+x] 208 x = x + 1 209 } 210 y = y + 1 211 } 212 write_png(combo, W2, VF_EH, outpath) 213 return 0 214} 215 216func main(argc: i64, argv: *i64) -> i64 { 217 var distort: i64 = 1 218 var outpath: *u8 = "knowledge/nx_vrframe.png" as *u8 219 if argc >= 2 { 220 let a1: *u8 = argv[1] as *u8 221 // `flat` -> the neg-control (no lens distortion); `pub` -> publish to the served site. 222 // ONE render+encode per call (the ~15s runner watchdog kills a double-encode). 223 if a1[0]==(102 as u8) { distort = 0; outpath = "knowledge/nx_vrframe_flat.png" as *u8 } 224 if a1[0]==(112 as u8) { outpath = "sites/nishifamily/world/vrframe.png" as *u8 } 225 } 226 vf_build(distort, outpath) 227 vw2("{\x22organ\x22:\x22nx_vrframe\x22,\x22verb\x22:\x22compose\x22,\x22eye\x22:[" as *u8) 228 vn2(VF_EW); vw2("," as *u8); vn2(VF_EH) 229 vw2("],\x22frame\x22:[" as *u8); vn2(VF_EW*2); vw2("," as *u8); vn2(VF_EH) 230 vw2("],\x22ipd_units\x22:" as *u8); vn2(VF_IPD*2) 231 vw2(",\x22distortion\x22:\x22radial barrel k1=" as *u8); vn2(VF_K1) 232 vw2(" k2=" as *u8); vn2(VF_K2) 233 vw2(" (OpenXR lens-correction inverse)\x22,\x22distort_applied\x22:" as *u8); vn2(distort) 234 vw2(",\x22never_brick\x22:\x22by construction: pure compute + one regular-file PNG write; no device/firmware namespace\x22" as *u8) 235 vw2(",\x22path\x22:\x22" as *u8); vw2(outpath) 236 vw2("\x22,\x22published\x22:\x22sites/nishifamily/world/vrframe.png\x22}\x0a" as *u8) 237 return 0 238}