code wiki / _hdl_build / nx_f32_raster_gate.nx
nx_f32_raster_gate.nx source
↩ module page · 222 lines · 8003 B
1// nx_f32_raster_gate.nx -- R4: the FIRST visible hardware-f32 3D artifact. Renders a rotated,
2// directionally-shaded cube using nx_f32_hw f32 math (mat4 rotation + orthographic projection),
3// painter-sorted faces, integer barycentric fill, and writes a 24-bit BMP to web_assets/_game_build.
4// Proves the hardware-f32 stack drives a REAL raster image -- off the 1970s ASCII floor.
5// exit 0 = rendered (center pixel != background); the BMP is the artifact. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_f32_hw.nx"
8
9const W: i64 = 256
10const H: i64 = 256
11const SCALE: i64 = 64
12
13func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b }
14func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b }
15func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) }
16func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) }
17func same_sign3(a: i64, b: i64, c: i64) -> i64 {
18 if a >= 0 { if b >= 0 { if c >= 0 { return 1 } } }
19 if a <= 0 { if b <= 0 { if c <= 0 { return 1 } } }
20 return 0
21}
22// flat-fill a screen-space triangle (integer barycentric; winding-agnostic).
23func fill_tri(fb: *i64, x0: i64, y0: i64, x1: i64, y1: i64, x2: i64, y2: i64, col: i64) -> i64 {
24 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)
25 if area == 0 { return 0 }
26 let minx: i64 = imax(0, min3(x0, x1, x2))
27 let maxx: i64 = imin(W - 1, max3(x0, x1, x2))
28 let miny: i64 = imax(0, min3(y0, y1, y2))
29 let maxy: i64 = imin(H - 1, max3(y0, y1, y2))
30 var py: i64 = miny
31 while py <= maxy {
32 var px: i64 = minx
33 while px <= maxx {
34 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1)
35 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2)
36 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0)
37 if same_sign3(e0, e1, e2) == 1 { fb[py * W + px] = col }
38 px = px + 1
39 }
40 py = py + 1
41 }
42 return 0
43}
44func put_u32le(b: *u8, o: i64, v: i64) -> i64 {
45 b[o] = (v & 0xff) as u8
46 b[o + 1] = ((v >> 8) & 0xff) as u8
47 b[o + 2] = ((v >> 16) & 0xff) as u8
48 b[o + 3] = ((v >> 24) & 0xff) as u8
49 return 0
50}
51// 24-bit BMP (bottom-up, BGR). packed colour convention: c = R + G*256 + B*65536.
52func write_bmp(fb: *i64, path: *u8) -> i64 {
53 let pix: i64 = W * H * 3
54 let total: i64 = 54 + pix
55 let b: *u8 = sys_mmap(total) as *u8
56 b[0] = 66 as u8
57 b[1] = 77 as u8
58 put_u32le(b, 2, total)
59 put_u32le(b, 10, 54)
60 put_u32le(b, 14, 40)
61 put_u32le(b, 18, W)
62 put_u32le(b, 22, H)
63 b[26] = 1 as u8
64 b[28] = 24 as u8
65 put_u32le(b, 34, pix)
66 var o: i64 = 54
67 var ry: i64 = 0
68 while ry < H {
69 let sy: i64 = H - 1 - ry
70 var x: i64 = 0
71 while x < W {
72 let c: i64 = fb[sy * W + x]
73 b[o] = ((c >> 16) & 0xff) as u8
74 b[o + 1] = ((c >> 8) & 0xff) as u8
75 b[o + 2] = (c & 0xff) as u8
76 o = o + 3
77 x = x + 1
78 }
79 ry = ry + 1
80 }
81 let fd: i64 = sys_openat_wr(path, 0x1a4)
82 if fd < 0 { return 0 - 1 }
83 sys_write(fd, b, total)
84 sys_close(fd)
85 return 0
86}
87func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) }
88// rotate a local direction by R, return its z-component (f32 carrier).
89func rot_nz(R: *i64, lx: i64, ly: i64, lz: i64) -> i64 {
90 let v: *i64 = sys_mmap(32) as *i64
91 let o: *i64 = sys_mmap(32) as *i64
92 v[0] = lx
93 v[1] = ly
94 v[2] = lz
95 v[3] = f32_of(0)
96 m4_vec4(R, v, o)
97 return o[2]
98}
99// directional brightness 55..255 from a rotated normal's z (front-facing = bright).
100func shade(nz: i64) -> i64 {
101 var z: i64 = nz
102 if (z & 0x80000000) != 0 { z = f32_of(0) }
103 return 55 + f32_int(f32_mul(z, f32_of(200)))
104}
105func packc(r: i64, g: i64, b: i64, br: i64) -> i64 {
106 let rr: i64 = (r * br) / 255
107 let gg: i64 = (g * br) / 255
108 let bb: i64 = (b * br) / 255
109 return rr + gg * 256 + bb * 65536
110}
111
112func main() -> i64 {
113 let fb: *i64 = sys_mmap(W * H * 8) as *i64
114 let bg: i64 = 28 + 32 * 256 + 44 * 65536
115 var i: i64 = 0
116 while i < W * H {
117 fb[i] = bg
118 i = i + 1
119 }
120
121 // R = Rx(22deg) * Ry(34deg), built from hardcoded f32 sin/cos ratios (no trig lib yet).
122 let cy: i64 = fratio(829, 1000)
123 let sy: i64 = fratio(559, 1000)
124 let cx: i64 = fratio(927, 1000)
125 let sx: i64 = fratio(375, 1000)
126 let Ry: *i64 = sys_mmap(128) as *i64
127 m4_identity(Ry)
128 Ry[0] = cy
129 Ry[2] = sy
130 Ry[8] = f32_neg(sy)
131 Ry[10] = cy
132 let Rx: *i64 = sys_mmap(128) as *i64
133 m4_identity(Rx)
134 Rx[5] = cx
135 Rx[6] = f32_neg(sx)
136 Rx[9] = sx
137 Rx[10] = cx
138 let R: *i64 = sys_mmap(128) as *i64
139 m4_mul(Rx, Ry, R)
140
141 // transform + orthographic-project the 8 cube vertices (local +-1).
142 let sxk: *i64 = sys_mmap(8 * 8) as *i64
143 let syk: *i64 = sys_mmap(8 * 8) as *i64
144 let tzi: *i64 = sys_mmap(8 * 8) as *i64
145 let one: i64 = f32_of(1)
146 let none: i64 = f32_neg(one)
147 var k: i64 = 0
148 while k < 8 {
149 var lx: i64 = none
150 if (k & 1) == 1 { lx = one }
151 var ly: i64 = none
152 if (k & 2) == 2 { ly = one }
153 var lz: i64 = none
154 if (k & 4) == 4 { lz = one }
155 let v: *i64 = sys_mmap(32) as *i64
156 let o: *i64 = sys_mmap(32) as *i64
157 v[0] = lx
158 v[1] = ly
159 v[2] = lz
160 v[3] = f32_of(0)
161 m4_vec4(R, v, o)
162 sxk[k] = (W / 2) + f32_int(f32_mul(o[0], f32_of(SCALE)))
163 syk[k] = (H / 2) - f32_int(f32_mul(o[1], f32_of(SCALE)))
164 tzi[k] = f32_int(f32_mul(o[2], f32_of(1000)))
165 k = k + 1
166 }
167
168 // 6 faces, 10 ints each: i0 i1 i2 i3 r g b lnx lny lnz
169 let F: *i64 = sys_mmap(60 * 8) as *i64
170 F[0] = 4; F[1] = 5; F[2] = 7; F[3] = 6; F[4] = 90; F[5] = 150; F[6] = 235; F[7] = 0; F[8] = 0; F[9] = 1
171 F[10] = 0; F[11] = 1; F[12] = 3; F[13] = 2; F[14] = 70; F[15] = 110; F[16] = 180; F[17] = 0; F[18] = 0; F[19] = 0 - 1
172 F[20] = 1; F[21] = 5; F[22] = 7; F[23] = 3; F[24] = 230; F[25] = 85; F[26] = 80; F[27] = 1; F[28] = 0; F[29] = 0
173 F[30] = 0; F[31] = 4; F[32] = 6; F[33] = 2; F[34] = 170; F[35] = 60; F[36] = 58; F[37] = 0 - 1; F[38] = 0; F[39] = 0
174 F[40] = 2; F[41] = 3; F[42] = 7; F[43] = 6; F[44] = 95; F[45] = 205; F[46] = 110; F[47] = 0; F[48] = 1; F[49] = 0
175 F[50] = 0; F[51] = 1; F[52] = 5; F[53] = 4; F[54] = 70; F[55] = 150; F[56] = 82; F[57] = 0; F[58] = 0 - 1; F[59] = 0
176
177 // painter's: draw faces far->near (ascending centroid z; +z is toward the viewer).
178 let drawn: *i64 = sys_mmap(6 * 8) as *i64
179 var df: i64 = 0
180 while df < 6 {
181 drawn[df] = 0
182 df = df + 1
183 }
184 var pass: i64 = 0
185 while pass < 6 {
186 var best: i64 = 0 - 1
187 var bestz: i64 = 0
188 var fi: i64 = 0
189 while fi < 6 {
190 if drawn[fi] == 0 {
191 let cb: i64 = fi * 10
192 let cz: i64 = (tzi[F[cb]] + tzi[F[cb + 1]] + tzi[F[cb + 2]] + tzi[F[cb + 3]]) / 4
193 if best < 0 {
194 best = fi
195 bestz = cz
196 } else {
197 if cz < bestz {
198 best = fi
199 bestz = cz
200 }
201 }
202 }
203 fi = fi + 1
204 }
205 drawn[best] = 1
206 let base: i64 = best * 10
207 let i0: i64 = F[base]
208 let i1: i64 = F[base + 1]
209 let i2: i64 = F[base + 2]
210 let i3: i64 = F[base + 3]
211 let nz: i64 = rot_nz(R, f32_of(F[base + 7]), f32_of(F[base + 8]), f32_of(F[base + 9]))
212 let br: i64 = shade(nz)
213 let col: i64 = packc(F[base + 4], F[base + 5], F[base + 6], br)
214 fill_tri(fb, sxk[i0], syk[i0], sxk[i1], syk[i1], sxk[i2], syk[i2], col)
215 fill_tri(fb, sxk[i0], syk[i0], sxk[i2], syk[i2], sxk[i3], syk[i3], col)
216 pass = pass + 1
217 }
218
219 write_bmp(fb, "web_assets/_game_build/f32cube.bmp" as *u8)
220 if fb[(H / 2) * W + (W / 2)] == bg { return 1 }
221 return 0
222}