code wiki / _hdl_build / nx_sphere_gate.nx

nx_sphere_gate.nx source

↩ module page · 244 lines · 10018 B

1// nx_sphere_gate.nx -- realism/anime on an OBJECT (not terrain): a smooth Gouraud-lit sphere on the sovereign 2// f32 raster path. Geometry = spherified cube (no trig; normalize a cube grid via nx_f32_sqrt, same bit layout 3// as hw f32). Per-vertex lambert brightness (normal=unit position) interpolated PER PIXEL = smooth shading. 4// Rendered twice: style 0 realism (smooth), style 1 toon (2-tone + black outline). 2 BMPs. exit 0 = rendered. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_f32_hw.nx" 8import "nx_f32.nx" 9 10const W: i64 = 320 11const H: i64 = 240 12const HW: i64 = 160 13const HH: i64 = 120 14const G: i64 = 10 // cells per cube-face edge (verts/edge = G+1) 15const VPF: i64 = 121 // (G+1)*(G+1) 16const NV: i64 = 726 // 6*VPF 17const FOCAL: i64 = 560 18const PUSH: i64 = 4 19const ZFAR: i64 = 1073741824 20 21func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b } 22func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } 23func iabs(a: i64) -> i64 { if a < 0 { return 0 - a } return a } 24func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) } 25func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) } 26func clamp255(v: i64) -> i64 { if v < 0 { return 0 } if v > 255 { return 255 } return v } 27func same_sign3(a: i64, b: i64, c: i64) -> i64 { 28 if a >= 0 { if b >= 0 { if c >= 0 { return 1 } } } 29 if a <= 0 { if b <= 0 { if c <= 0 { return 1 } } } 30 return 0 31} 32func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } 33 34func cube_pt(f: i64, u: i64, v: i64, out: *i64) -> i64 { 35 let one: i64 = f32_of(1) 36 let none: i64 = f32_neg(one) 37 if f == 0 { out[0] = one; out[1] = u; out[2] = v } 38 if f == 1 { out[0] = none; out[1] = u; out[2] = v } 39 if f == 2 { out[0] = u; out[1] = one; out[2] = v } 40 if f == 3 { out[0] = u; out[1] = none; out[2] = v } 41 if f == 4 { out[0] = u; out[1] = v; out[2] = one } 42 if f == 5 { out[0] = u; out[1] = v; out[2] = none } 43 return 0 44} 45// gouraud (per-vertex brightness) z-buffered triangle. t = [x0,y0,d0,b0, x1,y1,d1,b1, x2,y2,d2,b2]. 46func fill_gour(fb: *i64, zb: *i64, t: *i64, baseR: i64, baseG: i64, baseB: i64, style: i64) -> i64 { 47 let x0: i64 = t[0]; let y0: i64 = t[1]; let d0: i64 = t[2]; let b0: i64 = t[3] 48 let x1: i64 = t[4]; let y1: i64 = t[5]; let d1: i64 = t[6]; let b1: i64 = t[7] 49 let x2: i64 = t[8]; let y2: i64 = t[9]; let d2: i64 = t[10]; let b2: i64 = t[11] 50 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 51 if area == 0 { return 0 } 52 let minx: i64 = imax(0, min3(x0, x1, x2)) 53 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 54 let miny: i64 = imax(0, min3(y0, y1, y2)) 55 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 56 var py: i64 = miny 57 while py <= maxy { 58 var px: i64 = minx 59 while px <= maxx { 60 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 61 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 62 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 63 if same_sign3(e0, e1, e2) == 1 { 64 let d: i64 = (e0 * d0 + e1 * d1 + e2 * d2) / area 65 let idx: i64 = py * W + px 66 if d < zb[idx] { 67 zb[idx] = d 68 var bri: i64 = (e0 * b0 + e1 * b1 + e2 * b2) / area 69 if style == 1 { if bri < 145 { bri = 90 } else { bri = 235 } } 70 fb[idx] = ((baseR * bri) / 255) + ((baseG * bri) / 255) * 256 + ((baseB * bri) / 255) * 65536 71 } 72 } 73 px = px + 1 74 } 75 py = py + 1 76 } 77 return 0 78} 79func outline_pass(fb: *i64, zb: *i64) -> i64 { 80 var y: i64 = 1 81 while y < H - 1 { 82 var x: i64 = 1 83 while x < W - 1 { 84 let i: i64 = y * W + x 85 let d: i64 = zb[i] 86 if d < ZFAR { 87 var edge: i64 = 0 88 if zb[i - 1] == ZFAR { edge = 1 } 89 if zb[i + 1] == ZFAR { edge = 1 } 90 if zb[i - W] == ZFAR { edge = 1 } 91 if zb[i + W] == ZFAR { edge = 1 } 92 if edge == 1 { fb[i] = 0 } 93 } 94 x = x + 1 95 } 96 y = y + 1 97 } 98 return 0 99} 100func put_u32le(b: *u8, o: i64, v: i64) -> i64 { 101 b[o] = (v & 0xff) as u8 102 b[o + 1] = ((v >> 8) & 0xff) as u8 103 b[o + 2] = ((v >> 16) & 0xff) as u8 104 b[o + 3] = ((v >> 24) & 0xff) as u8 105 return 0 106} 107func write_bmp(fb: *i64, path: *u8) -> i64 { 108 let pix: i64 = W * H * 3 109 let total: i64 = 54 + pix 110 let b: *u8 = sys_mmap(total) as *u8 111 b[0] = 66 as u8 112 b[1] = 77 as u8 113 put_u32le(b, 2, total) 114 put_u32le(b, 10, 54) 115 put_u32le(b, 14, 40) 116 put_u32le(b, 18, W) 117 put_u32le(b, 22, H) 118 b[26] = 1 as u8 119 b[28] = 24 as u8 120 put_u32le(b, 34, pix) 121 var o: i64 = 54 122 var ry: i64 = 0 123 while ry < H { 124 let syrow: i64 = H - 1 - ry 125 var x: i64 = 0 126 while x < W { 127 let c: i64 = fb[syrow * W + x] 128 b[o] = ((c >> 16) & 0xff) as u8 129 b[o + 1] = ((c >> 8) & 0xff) as u8 130 b[o + 2] = (c & 0xff) as u8 131 o = o + 3 132 x = x + 1 133 } 134 ry = ry + 1 135 } 136 let fd: i64 = sys_openat_wr(path, 0x1a4) 137 if fd < 0 { return 0 - 1 } 138 sys_write(fd, b, total) 139 sys_close(fd) 140 return 0 141} 142// render the sphere: build verts (pos+brightness via spherified-cube + lambert), project, raster. 143func render_sphere(fb: *i64, zb: *i64, R: *i64, style: i64, baseR: i64, baseG: i64, baseB: i64, 144 sx: *i64, sy: *i64, sd: *i64, sok: *i64, sb: *i64) -> i64 { 145 let sky: i64 = 150 + 170 * 256 + 210 * 65536 146 var p: i64 = 0 147 while p < W * H { fb[p] = sky; zb[p] = ZFAR; p = p + 1 } 148 // light toward upper-front-camera (-z toward viewer). 149 let lx: i64 = fratio(3, 10) 150 let ly: i64 = fratio(5, 10) 151 let lz: i64 = f32_neg(fratio(8, 10)) 152 var f: i64 = 0 153 while f < 6 { 154 var j: i64 = 0 155 while j <= G { 156 var ii: i64 = 0 157 while ii <= G { 158 let u: i64 = fratio(2 * ii - G, G) 159 let v: i64 = fratio(2 * j - G, G) 160 let cp: *i64 = sys_mmap(32) as *i64 161 cube_pt(f, u, v, cp) 162 let l2: i64 = f32_add(f32_add(f32_mul(cp[0], cp[0]), f32_mul(cp[1], cp[1])), f32_mul(cp[2], cp[2])) 163 let len: i64 = nx_f32_sqrt(l2) 164 let nv: *i64 = sys_mmap(32) as *i64 165 nv[0] = f32_div(cp[0], len) 166 nv[1] = f32_div(cp[1], len) 167 nv[2] = f32_div(cp[2], len) 168 nv[3] = f32_of(0) 169 let rp: *i64 = sys_mmap(32) as *i64 170 m4_vec4(R, nv, rp) // rotated unit normal = rotated unit position 171 let g: i64 = f * VPF + j * (G + 1) + ii 172 // lambert: dot(rotated normal, light) 173 var bd: i64 = v3_dot(rp[0], rp[1], rp[2], lx, ly, lz) 174 if (bd & 0x80000000) != 0 { bd = f32_of(0) } 175 sb[g] = clamp255(45 + f32_int(f32_mul(bd, f32_of(210)))) 176 // project (sphere radius 1 at depth PUSH) 177 let pz: i64 = f32_add(rp[2], f32_of(PUSH)) 178 if (pz & 0x80000000) != 0 { sok[g] = 0 } else { 179 sx[g] = HW + f32_int(f32_div(f32_mul(rp[0], f32_of(FOCAL)), pz)) 180 sy[g] = HH - f32_int(f32_div(f32_mul(rp[1], f32_of(FOCAL)), pz)) 181 sd[g] = f32_int(f32_mul(pz, f32_of(256))) 182 sok[g] = 1 183 } 184 ii = ii + 1 185 } 186 j = j + 1 187 } 188 f = f + 1 189 } 190 // triangulate each face grid. 191 var ff: i64 = 0 192 while ff < 6 { 193 var cj: i64 = 0 194 while cj < G { 195 var ci: i64 = 0 196 while ci < G { 197 let a: i64 = ff * VPF + cj * (G + 1) + ci 198 let b: i64 = ff * VPF + cj * (G + 1) + ci + 1 199 let c: i64 = ff * VPF + (cj + 1) * (G + 1) + ci + 1 200 let dd: i64 = ff * VPF + (cj + 1) * (G + 1) + ci 201 if sok[a] == 1 { if sok[b] == 1 { if sok[c] == 1 { if sok[dd] == 1 { 202 let t: *i64 = sys_mmap(12 * 8) as *i64 203 t[0] = sx[a]; t[1] = sy[a]; t[2] = sd[a]; t[3] = sb[a] 204 t[4] = sx[b]; t[5] = sy[b]; t[6] = sd[b]; t[7] = sb[b] 205 t[8] = sx[c]; t[9] = sy[c]; t[10] = sd[c]; t[11] = sb[c] 206 fill_gour(fb, zb, t, baseR, baseG, baseB, style) 207 t[0] = sx[a]; t[1] = sy[a]; t[2] = sd[a]; t[3] = sb[a] 208 t[4] = sx[c]; t[5] = sy[c]; t[6] = sd[c]; t[7] = sb[c] 209 t[8] = sx[dd]; t[9] = sy[dd]; t[10] = sd[dd]; t[11] = sb[dd] 210 fill_gour(fb, zb, t, baseR, baseG, baseB, style) 211 } } } } 212 ci = ci + 1 213 } 214 cj = cj + 1 215 } 216 ff = ff + 1 217 } 218 if style == 1 { outline_pass(fb, zb) } 219 return 0 220} 221 222func main() -> i64 { 223 let fb: *i64 = sys_mmap(W * H * 8) as *i64 224 let zb: *i64 = sys_mmap(W * H * 8) as *i64 225 let sx: *i64 = sys_mmap(NV * 8) as *i64 226 let sy: *i64 = sys_mmap(NV * 8) as *i64 227 let sd: *i64 = sys_mmap(NV * 8) as *i64 228 let sok: *i64 = sys_mmap(NV * 8) as *i64 229 let sb: *i64 = sys_mmap(NV * 8) as *i64 230 let R: *i64 = sys_mmap(128) as *i64 231 let Rx: *i64 = sys_mmap(128) as *i64 232 let Ry: *i64 = sys_mmap(128) as *i64 233 m4_roty(fratio(940, 1000), fratio(342, 1000), Ry) 234 m4_rotx(fratio(966, 1000), fratio(259, 1000), Rx) 235 m4_mul(Rx, Ry, R) 236 237 render_sphere(fb, zb, R, 0, 226, 142, 70, sx, sy, sd, sok, sb) // realism, warm orange 238 write_bmp(fb, "web_assets/_game_build/sphere_real.bmp" as *u8) 239 render_sphere(fb, zb, R, 1, 226, 142, 70, sx, sy, sd, sok, sb) // toon 240 write_bmp(fb, "web_assets/_game_build/sphere_toon.bmp" as *u8) 241 242 if fb[(H / 2) * W + (W / 2)] == 0 { return 1 } 243 return 0 244}