code wiki / (root) / nx_depth_tri.nx

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}