nx_depth_tri.nx source
↩ module page · 73 lines · 3029 B
1// nx_depth_tri.nx -- Z-BUFFERED triangle rasterizer: the primitive that turns a flat textured quad into a real
2// 3D scene. Barycentric depth interpolation (SAME DDA math as UV), a per-fragment DEPTH TEST against a z-buffer,
3// so overlapping triangles resolve OCCLUSION order-independently -- the gateway from 2D blit to 3D (procgen
4// worlds + beings render with correct visibility). Pure integer, deterministic. license_tier: ORIGINAL
5// zbuf: i64 per pixel, SMALLER z == NEARER (init to a large "far" sentinel via depth_clear).
6// depth_on=1 => depth-tested (order-independent). depth_on=0 => painter's (last-writer-wins) = neg-control.
7// z0/z1/z2 = per-vertex depth (any fixed-point scale); interpolated barycentrically like UV.
8import "nx_syscalls.nx"
9import "nx_image.nx"
10
11func dt_edge(ax: i64, ay: i64, bx: i64, by: i64, px: i64, py: i64) -> i64 {
12 return (bx - ax) * (py - ay) - (by - ay) * (px - ax)
13}
14
15func depth_clear(zbuf: *i64, n: i64, val: i64) -> i64 {
16 var i: i64 = 0
17 while i < n { zbuf[i] = val; i = i + 1 }
18 return 0
19}
20
21func depth_tri_render(fb: *Image, zbuf: *i64, x0: i64, y0: i64, z0: i64, x1: i64, y1: i64, z1: i64, x2: i64, y2: i64, z2: i64, rr: i64, gg: i64, bb: i64, depth_on: i64) -> i64 {
22 var area: i64 = dt_edge(x0, y0, x1, y1, x2, y2)
23 if area == 0 { return 0 }
24 var sgn: i64 = 1
25 if area < 0 { sgn = 0 - 1; area = 0 - area }
26 var minx: i64 = x0
27 if x1 < minx { minx = x1 }
28 if x2 < minx { minx = x2 }
29 var maxx: i64 = x0
30 if x1 > maxx { maxx = x1 }
31 if x2 > maxx { maxx = x2 }
32 var miny: i64 = y0
33 if y1 < miny { miny = y1 }
34 if y2 < miny { miny = y2 }
35 var maxy: i64 = y0
36 if y1 > maxy { maxy = y1 }
37 if y2 > maxy { maxy = y2 }
38 if minx < 0 { minx = 0 }
39 if miny < 0 { miny = 0 }
40 if maxx >= fb.width { maxx = fb.width - 1 }
41 if maxy >= fb.height { maxy = fb.height - 1 }
42 let px: *u8 = fb.pixels
43 let w: i64 = fb.width
44 var py: i64 = miny
45 while py <= maxy {
46 var pxi: i64 = minx
47 while pxi <= maxx {
48 let w0: i64 = dt_edge(x1, y1, x2, y2, pxi, py) * sgn
49 let w1: i64 = dt_edge(x2, y2, x0, y0, pxi, py) * sgn
50 let w2: i64 = dt_edge(x0, y0, x1, y1, pxi, py) * sgn
51 if w0 >= 0 {
52 if w1 >= 0 {
53 if w2 >= 0 {
54 let z: i64 = (w0 * z0 + w1 * z1 + w2 * z2) / area
55 let zi: i64 = py * w + pxi
56 var wr: i64 = 0
57 if depth_on == 0 { wr = 1 } else { if z < zbuf[zi] { wr = 1 } }
58 if wr == 1 {
59 zbuf[zi] = z
60 let off: i64 = py * fb.stride + pxi * 3
61 px[off] = rr as u8
62 px[off + 1] = gg as u8
63 px[off + 2] = bb as u8
64 }
65 }
66 }
67 }
68 pxi = pxi + 1
69 }
70 py = py + 1
71 }
72 return 0
73}