code wiki / (root) / nx_gpu_geometry.nx

nx_gpu_geometry.nx source

↩ module page · 124 lines · 9175 B

1// nx_gpu_geometry.nx -- GOAL-GPU-NATIVE rung-3: the 3D GEOMETRY STAGE (transform + project + hidden-surface). 2// Turns flat 2D triangles into real moving 3D -- the front of the graphics pipeline, the last pure-software 3// rung before the silicon unlock. A unit cube (8 verts, 12 triangles, 6 coloured faces) is rotated (Y then 4// X, integer fixed-point cos/sin x256), perspective-projected to screen space, and rasterized with the rung-1 5// Z-BUFFER doing HIDDEN-SURFACE REMOVAL -- so only the front faces show, back faces are occluded by depth. 6// Two frames at different angles prove the rotation is real geometry, not a static picture. 7// KAT: the cube renders; HIDDEN-SURFACE is correct (a cube shows at most 3 faces -> <=3 face colours visible, 8// proving back faces were depth-occluded); rotating the angle changes the projection (frame0 != frame1); 9// frames export to BMP. All integer, fully sovereign. Feeds the GPFIFO graphics path (rung-2) as draw cmds. 10// (cube geometry packed into one `mesh` array: verts x@0..7 y@8..15 z@16..23; tris a@24 b@36 c@48 r@60 g@72 b@84.) 11// HONEST SCOPE: flat per-triangle depth/shading + fixed angles; smooth animation + per-pixel depth + lighting 12// are refinements; real-time perf needs the silicon last-mile. No hw writes (Rule 26). expect_exit: 0 tier: ORIGINAL 13import "nx_fb.nx" 14 15func gm_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 16func gm_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 17func gm_edge(ax: i64, ay: i64, bx: i64, by: i64, px: i64, py: i64) -> i64 { return (bx-ax)*(py-ay) - (by-ay)*(px-ax) } 18func gm_min3(a: i64, b: i64, c: i64) -> i64 { var m: i64=a; if b<m {m=b} if c<m {m=c} return m } 19func gm_max3(a: i64, b: i64, c: i64) -> i64 { var m: i64=a; if b>m {m=b} if c>m {m=c} return m } 20func gm_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 21 22func gm_project(vx: i64, vy: i64, vz: i64, cy: i64, sy: i64, cx: i64, sx: i64, W: i64, H: i64, out: *i64) -> i64 { 23 let xr: i64=(vx*cy - vz*sy)/256 24 let zr: i64=(vx*sy + vz*cy)/256 25 let yr: i64=vy 26 let yr2: i64=(yr*cx - zr*sx)/256 27 let zr2: i64=(yr*sx + zr*cx)/256 28 let depth: i64=zr2 + 260 29 out[0]=W/2 + (xr*300)/depth 30 out[1]=H/2 - (yr2*300)/depth 31 out[2]=depth 32 return 0 33} 34func gm_tri(fb: *u8, zbuf: *i64, W: i64, H: i64, x0: i64, y0: i64, x1: i64, y1: i64, x2: i64, y2: i64, z: i64, r: i64, g: i64, b: i64) -> i64 { 35 let area: i64=gm_edge(x0,y0,x1,y1,x2,y2) 36 if area==0 { return 0 } 37 let minx: i64=gm_clamp(gm_min3(x0,x1,x2),0,W-1); let maxx: i64=gm_clamp(gm_max3(x0,x1,x2),0,W-1) 38 let miny: i64=gm_clamp(gm_min3(y0,y1,y2),0,H-1); let maxy: i64=gm_clamp(gm_max3(y0,y1,y2),0,H-1) 39 var py: i64=miny 40 while py<=maxy { 41 var px: i64=minx 42 while px<=maxx { 43 let w0: i64=gm_edge(x1,y1,x2,y2,px,py); let w1: i64=gm_edge(x2,y2,x0,y0,px,py); let w2: i64=gm_edge(x0,y0,x1,y1,px,py) 44 var inside: i64=0 45 if area>0 { if w0>=0 { if w1>=0 { if w2>=0 { inside=1 } } } } else { if w0<=0 { if w1<=0 { if w2<=0 { inside=1 } } } } 46 if inside==1 { let idx: i64=py*W+px; if z<zbuf[idx] { zbuf[idx]=z; let o: i64=(py*W+px)*3; fb[o]=r as u8; fb[o+1]=g as u8; fb[o+2]=b as u8 } } 47 px=px+1 48 } 49 py=py+1 50 } 51 return 0 52} 53func render_cube(fb: *u8, zbuf: *i64, W: i64, H: i64, cy: i64, sy: i64, cx: i64, sx: i64, mesh: *i64) -> i64 { 54 let FAR: i64=1<<30 55 var i: i64=0 56 while i<W*H { let o: i64=i*3; fb[o]=18 as u8; fb[o+1]=18 as u8; fb[o+2]=28 as u8; zbuf[i]=FAR; i=i+1 } 57 let sxv: *i64=sys_mmap(8*8); let syv: *i64=sys_mmap(8*8); let dv: *i64=sys_mmap(8*8) 58 let tmp: *i64=sys_mmap(8*4) 59 var v: i64=0 60 while v<8 { gm_project(mesh[v],mesh[8+v],mesh[16+v], cy,sy,cx,sx, W,H, tmp); sxv[v]=tmp[0]; syv[v]=tmp[1]; dv[v]=tmp[2]; v=v+1 } 61 var t: i64=0 62 while t<12 { 63 let a: i64=mesh[24+t]; let bb: i64=mesh[36+t]; let cc: i64=mesh[48+t] 64 let depth: i64=(dv[a]+dv[bb]+dv[cc])/3 65 gm_tri(fb,zbuf,W,H, sxv[a],syv[a], sxv[bb],syv[bb], sxv[cc],syv[cc], depth, mesh[60+t],mesh[72+t],mesh[84+t]) 66 t=t+1 67 } 68 return 0 69} 70func setv(mesh: *i64, v: i64, x: i64, y: i64, z: i64) -> i64 { mesh[v]=x; mesh[8+v]=y; mesh[16+v]=z; return 0 } 71func settri(mesh: *i64, t: i64, a: i64, b: i64, c: i64, r: i64, g: i64, bl: i64) -> i64 { mesh[24+t]=a; mesh[36+t]=b; mesh[48+t]=c; mesh[60+t]=r; mesh[72+t]=g; mesh[84+t]=bl; return 0 } 72 73func main() -> i64 { 74 gm_puts("GOAL-GPU-NATIVE rung-3: 3D GEOMETRY STAGE (rotating cube: transform + project + z-buffer hidden-surface)\n" as *u8) 75 let W: i64=160 76 let H: i64=120 77 let mesh: *i64=sys_mmap(8*96) 78 setv(mesh,0,0-50,0-50,0-50); setv(mesh,1,50,0-50,0-50); setv(mesh,2,50,50,0-50); setv(mesh,3,0-50,50,0-50) 79 setv(mesh,4,0-50,0-50,50); setv(mesh,5,50,0-50,50); setv(mesh,6,50,50,50); setv(mesh,7,0-50,50,50) 80 settri(mesh,0, 0,1,2, 210,60,60); settri(mesh,1, 0,2,3, 210,60,60) // front red 81 settri(mesh,2, 5,4,7, 60,210,60); settri(mesh,3, 5,7,6, 60,210,60) // back green 82 settri(mesh,4, 4,0,3, 60,60,210); settri(mesh,5, 4,3,7, 60,60,210) // left blue 83 settri(mesh,6, 1,5,6, 210,200,60); settri(mesh,7, 1,6,2, 210,200,60) // right yellow 84 settri(mesh,8, 3,2,6, 60,200,200); settri(mesh,9, 3,6,7, 60,200,200) // top cyan 85 settri(mesh,10, 4,5,1, 210,60,200); settri(mesh,11, 4,1,0, 210,60,200) // bottom magenta 86 87 let fb0: *u8=sys_mmap(W*H*3); let zb0: *i64=sys_mmap(W*H*8) as *i64 88 let fb1: *u8=sys_mmap(W*H*3); let zb1: *i64=sys_mmap(W*H*8) as *i64 89 render_cube(fb0, zb0, W, H, 210,147, 232,108, mesh) // Y=35deg X=25deg 90 render_cube(fb1, zb1, W, H, 88,241, 232,108, mesh) // Y=70deg X=25deg 91 92 let fcr: *i64=sys_mmap(8*6); let fcg: *i64=sys_mmap(8*6); let fcb: *i64=sys_mmap(8*6) 93 fcr[0]=210;fcg[0]=60;fcb[0]=60; fcr[1]=60;fcg[1]=210;fcb[1]=60; fcr[2]=60;fcg[2]=60;fcb[2]=210; fcr[3]=210;fcg[3]=200;fcb[3]=60; fcr[4]=60;fcg[4]=200;fcb[4]=200; fcr[5]=210;fcg[5]=60;fcb[5]=200 94 let seen: *i64=sys_mmap(8*6); var si: i64=0; while si<6 { seen[si]=0; si=si+1 } 95 var covered: i64=0 96 var diff: i64=0 97 var p: i64=0 98 while p<W*H { 99 let o: i64=p*3 100 if zb0[p]<(1<<30) { covered=covered+1; var f: i64=0; while f<6 { if (fb0[o] as i64)==fcr[f] { if (fb0[o+1] as i64)==fcg[f] { if (fb0[o+2] as i64)==fcb[f] { seen[f]=1 } } } f=f+1 } } 101 if (fb0[o] as i64)!=(fb1[o] as i64) { diff=diff+1 } 102 p=p+1 103 } 104 var faces_visible: i64=0 105 si=0; while si<6 { if seen[si]==1 { faces_visible=faces_visible+1 } si=si+1 } 106 107 let s0: i64 = fb_bmp_save(fb0, W, H, "knowledge/status/nishios_cube0.bmp\x00" as *u8) 108 let s1: i64 = fb_bmp_save(fb1, W, H, "knowledge/status/nishios_cube1.bmp\x00" as *u8) 109 let hd: i64 = sys_openat_wr("knowledge/status/nishios_cube.html\x00" as *u8, 0x1a4) 110 if hd>0 { let html: *u8 = "<!doctype html><html><body style=\x27background:#0a0a12;color:#8af;font-family:monospace;text-align:center\x27><h3>NishiOS 3D geometry stage: rotating cube (transform+project+z-buffer)</h3><div style=\x27display:flex;gap:20px;justify-content:center\x27><div>Y=35deg<br><img src=\x27nishios_cube0.bmp\x27 style=\x27image-rendering:pixelated;width:400px;border:1px solid #333\x27></div><div>Y=70deg<br><img src=\x27nishios_cube1.bmp\x27 style=\x27image-rendering:pixelated;width:400px;border:1px solid #333\x27></div></div></body></html>\x00"; var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) } 111 112 gm_puts(" cube covered="); gm_num(covered); gm_puts(" faces_visible="); gm_num(faces_visible); gm_puts(" (<=3 = hidden-surface OK) frame0-vs-frame1 diff px="); gm_num(diff); gm_puts("\n" as *u8) 113 114 var pass: i64=0 115 var ttl: i64=0 116 ttl=ttl+1; gm_puts(" T1 cube rendered (covered>800): " as *u8); if covered>800 { pass=pass+1; gm_puts("PASS\n" as *u8) } else { gm_puts("FAIL\n" as *u8) } 117 ttl=ttl+1; gm_puts(" T2 hidden-surface correct (<=3 cube faces visible, back faces depth-occluded): " as *u8); if faces_visible>=1 { if faces_visible<=3 { pass=pass+1; gm_puts("PASS\n" as *u8) } else { gm_puts("FAIL\n" as *u8) } } else { gm_puts("FAIL\n" as *u8) } 118 ttl=ttl+1; gm_puts(" T3 rotation changes the projection (frame0 != frame1): " as *u8); if diff>500 { pass=pass+1; gm_puts("PASS\n" as *u8) } else { gm_puts("FAIL\n" as *u8) } 119 ttl=ttl+1; gm_puts(" T4 both frames exported to BMP: " as *u8); if s0>0 { if s1>0 { pass=pass+1; gm_puts("PASS\n" as *u8) } else { gm_puts("FAIL\n" as *u8) } } else { gm_puts("FAIL\n" as *u8) } 120 121 gm_puts("NISHIOS-GEOMETRY-GATE passed "); gm_num(pass); gm_puts("/"); gm_num(ttl) 122 if pass==ttl { gm_puts(" verdict=GREEN (real 3D geometry: transform+project+hidden-surface, a rotating cube -- the pipeline front-end)\n" as *u8); sys_exit(0); return 0 } 123 gm_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 124}