nx_raster_triangle.nx
buildroot/runtime/nx_raster_triangle.nx
about
nx_raster_triangle.nx -- software triangle rasterizer with Z-buffer.
LINEAGE (per [[feedback-no-tool-proliferation-consolidate-or-justify]]
cardinal landed 2026-05-20):
Distinct from [[nx_raster.nx]] because: nx_raster.nx ships
Bresenham lines + Pineda triangles + shaded triangles on the
*Image abstraction; this file is the *i64-framebuffer + Z-buffer
variant for 3D rendering with depth occlusion.
Distinct from [[nx_raster_sw.nx]] because: nx_raster_sw.nx is the
2D strict-interior coverage variant for perceptual-render demos
without depth; this file adds Z-buffer for 3D occlusion. The
two compose: this file CALLS nx_raster_sw's edge function in its
Pineda inner loop.
HONEST PROLIFERATION NOTE: three rasterizer primitives exist in
the substrate by 2026-05-20. Future raster work MUST extend one
of these three; consolidate if the substrate hits four.
Generic 3D substrate primitive per the placement cardinal
`feedback-nishi-lang-vs-nishi-engine-placement-discipline`.
Any program that renders 3D triangles uses this; not voxel-
specific. Lives in nishi-core/nxc2/runtime/.
Algorithm: edge-function rasterization (Pineda 1988). Per-pixel:
compute three signed edge values from the triangle's three edges;
pixel is inside the triangle if all three have the same sign.
Barycentric interpolation gives the per-pixel Z-depth used for
depth-buffered occlusion. No sub-pixel precision (integer
coordinates only) -- chunky pixels are the aesthetic for the
software-rendered /voxels path.
Vertex layout (matches nx_voxel_mesh):
verts[3*i + 0] = x_pixel (integer screen X)
verts[3*i + 1] = y_pixel (integer screen Y)
verts[3*i + 2] = z_q14_depth (Q14; smaller = closer)
verts[3*i + 3] = packed_color (u32 RGBA in low 32 bits)
Triangle list: vertices [0..3) are triangle 0, [3..6) are
dependencies 2 imports · 2 importers
imports: nx_syscalls.nxnx_tier.nx
imported by: nx_dx_exceed_census.nxnx_pets_voxel3d.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 72 | const NX_MAGIC_65536: i64 = 65536 |
| 73 | const NX_MAGIC_16777216: i64 = 16777216 |
| 74 | const NX_MAGIC_4294901695: i64 = 4294901695 |
| 75 | const NX_MAGIC_4294967040: i64 = 4294967040 |
| 76 | const NX_MAGIC_4278190335: i64 = 4278190335 |
| 77 | const NX_MAGIC_11111: i64 = 11111 |
| 78 | const NX_MAGIC_22222: i64 = 22222 |
| 83 | const NX_RASTER_Q: nx_int = 16384 |
| 88 | const NX_RASTER_Z_FAR: nx_int = 16384000 |
| 91 | const NX_RASTER_VERT_STRIDE: nx_int = 4 |
| 94 | const NX_RASTER_TRI_STRIDE: nx_int = 12 |
| 97 | const NX_RASTER_VOFF_X: nx_int = 0 |
| 98 | const NX_RASTER_VOFF_Y: nx_int = 1 |
| 99 | const NX_RASTER_VOFF_Z: nx_int = 2 |
| 100 | const NX_RASTER_VOFF_COLOR: nx_int = 3 |
functions
| 103 | func _min3(a: nx_int, b: nx_int, c: nx_int) -> nx_int called by 1: nx_raster_triangle |
| 110 | func _max3(a: nx_int, b: nx_int, c: nx_int) -> nx_int called by 1: nx_raster_triangle |
| 117 | func _clamp(v: nx_int, lo: nx_int, hi: nx_int) -> nx_int called by 1: nx_raster_triangle |
| 129 | func _same_sign_3(a: nx_int, b: nx_int, c: nx_int) -> nx_int called by 1: nx_raster_triangle |
| 147 | func nx_raster_alloc_fb(w: nx_int, h: nx_int) -> *i64 |
| 151 | func nx_raster_alloc_zb(w: nx_int, h: nx_int) -> *i64 |
| 156 | func nx_raster_clear(fb: *i64, w: nx_int, h: nx_int, color: nx_int) |
| 165 | func nx_raster_zbuffer_clear(zb: *i64, w: nx_int, h: nx_int) |
| 187 | func nx_raster_triangle( |
| 279 | func nx_raster_triangle_list( |
| 297 | func nx_raster_pixel(fb: *i64, w: nx_int, x: nx_int, y: nx_int) -> nx_int |
| 301 | func nx_raster_depth(zb: *i64, w: nx_int, x: nx_int, y: nx_int) -> nx_int called by 1: main |
| 306 | func main() -> i64 |