code wiki / (root) / nx_raster2d_lib.nx

nx_raster2d_lib.nx source

↩ module page · 194 lines · 7266 B

1// nx_raster2d_lib.nx -- shared 2D raster primitives on an i64 framebuffer (one i64/pixel, packed 2// R + G*256 + B*65536, the nx_png.write_png contract). Extracted VERBATIM from the gate-proven 3// nx_eco_graph_png (2026-07-16, byte-identical output gate) so the lineage renderer and the 4// whole-forest renderer share ONE implementation. Composes nx_font_bitmap_5x7 for text. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_eco_graph.nx" 8import "nx_font_bitmap_5x7.nx" 9const K_MAGIC_65536: i64 = 65536 10const K_MAGIC_6000: i64 = 6000 11 12func r2_px(fb: *i64, W: i64, H: i64, x: i64, y: i64, r: i64, gg: i64, b: i64) -> i64 { 13 if x < 0 { return 0 } 14 if y < 0 { return 0 } 15 if x >= W { return 0 } 16 if y >= H { return 0 } 17 fb[y*W + x] = r + gg*256 + b*K_MAGIC_65536 18 return 0 19} 20func r2_fill_rect(fb: *i64, W: i64, H: i64, x0: i64, y0: i64, w: i64, h: i64, r: i64, gg: i64, b: i64) -> i64 { 21 var yy: i64 = y0 22 while yy < y0 + h { var xx: i64 = x0; while xx < x0 + w { r2_px(fb,W,H,xx,yy,r,gg,b); xx = xx + 1 } yy = yy + 1 } 23 return 0 24} 25func r2_fill_disk(fb: *i64, W: i64, H: i64, cx: i64, cy: i64, rad: i64, r: i64, gg: i64, b: i64) -> i64 { 26 var dy: i64 = 0 - rad 27 while dy <= rad { 28 var dx: i64 = 0 - rad 29 while dx <= rad { 30 if dx*dx + dy*dy <= rad*rad { r2_px(fb,W,H,cx+dx,cy+dy,r,gg,b) } 31 dx = dx + 1 32 } 33 dy = dy + 1 34 } 35 return 0 36} 37func r2_ring(fb: *i64, W: i64, H: i64, cx: i64, cy: i64, rad: i64, r: i64, gg: i64, b: i64) -> i64 { 38 let r2hi: i64 = rad*rad 39 let r2lo: i64 = (rad-2)*(rad-2) 40 var dy: i64 = 0 - rad 41 while dy <= rad { 42 var dx: i64 = 0 - rad 43 while dx <= rad { 44 let d: i64 = dx*dx + dy*dy 45 if d <= r2hi { if d >= r2lo { r2_px(fb,W,H,cx+dx,cy+dy,r,gg,b) } } 46 dx = dx + 1 47 } 48 dy = dy + 1 49 } 50 return 0 51} 52func r2_line(fb: *i64, W: i64, H: i64, x0: i64, y0: i64, x1: i64, y1: i64, r: i64, gg: i64, b: i64) -> i64 { 53 var x: i64 = x0; var y: i64 = y0 54 var dx: i64 = x1 - x0; if dx < 0 { dx = 0 - dx } 55 var dy: i64 = y1 - y0; if dy < 0 { dy = 0 - dy } 56 var sx: i64 = 1; if x1 < x0 { sx = 0 - 1 } 57 var sy: i64 = 1; if y1 < y0 { sy = 0 - 1 } 58 var err: i64 = dx - dy 59 var guard: i64 = 0 60 while guard < K_MAGIC_6000 { 61 r2_px(fb,W,H,x,y,r,gg,b) 62 if x == x1 { if y == y1 { guard = K_MAGIC_6000 } } 63 if guard < K_MAGIC_6000 { 64 let e2: i64 = err + err 65 if e2 > (0 - dy) { err = err - dy; x = x + sx } 66 if e2 < dx { err = err + dx; y = y + sy } 67 guard = guard + 1 68 } 69 } 70 return 0 71} 72// ---- ADDITIVE variants: accumulate brightness (clamped) instead of overwriting. The hairball cure 73// for dense graphs: one edge is faint, a bundle glows -- an edge-density map, no alpha channel needed. ---- 74func r2_px_add(fb: *i64, W: i64, H: i64, x: i64, y: i64, dr: i64, dg: i64, db: i64) -> i64 { 75 if x < 0 { return 0 } 76 if y < 0 { return 0 } 77 if x >= W { return 0 } 78 if y >= H { return 0 } 79 let c: i64 = fb[y*W + x] 80 var r: i64 = c % 256 + dr 81 var g: i64 = (c / 256) % 256 + dg 82 var b: i64 = (c / K_MAGIC_65536) % 256 + db 83 if r > 255 { r = 255 } 84 if g > 255 { g = 255 } 85 if b > 255 { b = 255 } 86 fb[y*W + x] = r + g*256 + b*K_MAGIC_65536 87 return 0 88} 89func r2_line_add(fb: *i64, W: i64, H: i64, x0: i64, y0: i64, x1: i64, y1: i64, dr: i64, dg: i64, db: i64) -> i64 { 90 var x: i64 = x0; var y: i64 = y0 91 var dx: i64 = x1 - x0; if dx < 0 { dx = 0 - dx } 92 var dy: i64 = y1 - y0; if dy < 0 { dy = 0 - dy } 93 var sx: i64 = 1; if x1 < x0 { sx = 0 - 1 } 94 var sy: i64 = 1; if y1 < y0 { sy = 0 - 1 } 95 var err: i64 = dx - dy 96 var guard: i64 = 0 97 while guard < K_MAGIC_6000 { 98 r2_px_add(fb,W,H,x,y,dr,dg,db) 99 if x == x1 { if y == y1 { guard = K_MAGIC_6000 } } 100 if guard < K_MAGIC_6000 { 101 let e2: i64 = err + err 102 if e2 > (0 - dy) { err = err - dy; x = x + sx } 103 if e2 < dx { err = err + dx; y = y + sy } 104 guard = guard + 1 105 } 106 } 107 return 0 108} 109func r2_ribbon_add(fb: *i64, W: i64, H: i64, x1: i64, y1: i64, x2: i64, y2: i64, dr: i64, dg: i64, db: i64) -> i64 { 110 let my: i64 = (y1 + y2) / 2 111 var px: i64 = x1; var py: i64 = y1 112 var i: i64 = 1 113 while i <= 18 { 114 let t: i64 = i * 1000 / 18 115 let u: i64 = 1000 - t 116 let uu: i64 = u*u/1000 117 let tt: i64 = t*t/1000 118 let uuu: i64 = uu*u/1000 119 let ttt: i64 = tt*t/1000 120 let c0: i64 = uuu 121 let c1: i64 = 3*uu*t/1000 122 let c2: i64 = 3*u*tt/1000 123 let c3: i64 = ttt 124 let bx: i64 = (c0*x1 + c1*x1 + c2*x2 + c3*x2) / 1000 125 let by: i64 = (c0*y1 + c1*my + c2*my + c3*y2) / 1000 126 r2_line_add(fb,W,H,px,py,bx,by,dr,dg,db) 127 px = bx; py = by 128 i = i + 1 129 } 130 return 0 131} 132 133// cubic bezier ribbon P0(x1,y1) C(x1,my)(x2,my) P3(x2,y2) sampled into 18 segments 134func r2_ribbon(fb: *i64, W: i64, H: i64, x1: i64, y1: i64, x2: i64, y2: i64, r: i64, gg: i64, b: i64) -> i64 { 135 let my: i64 = (y1 + y2) / 2 136 var px: i64 = x1; var py: i64 = y1 137 var i: i64 = 1 138 while i <= 18 { 139 let t: i64 = i * 1000 / 18 140 let u: i64 = 1000 - t 141 let uu: i64 = u*u/1000 142 let tt: i64 = t*t/1000 143 let uuu: i64 = uu*u/1000 144 let ttt: i64 = tt*t/1000 145 let c0: i64 = uuu 146 let c1: i64 = 3*uu*t/1000 147 let c2: i64 = 3*u*tt/1000 148 let c3: i64 = ttt 149 let bx: i64 = (c0*x1 + c1*x1 + c2*x2 + c3*x2) / 1000 150 let by: i64 = (c0*y1 + c1*my + c2*my + c3*y2) / 1000 151 r2_line(fb,W,H,px,py,bx,by,r,gg,b) 152 px = bx; py = by 153 i = i + 1 154 } 155 return 0 156} 157// 5x7 glyph blit at scale; leftmost pixel = bit4. '_' not in font -> synth bottom row. 158func r2_char(fb: *i64, W: i64, H: i64, x: i64, y: i64, ch: i64, r: i64, gg: i64, b: i64, scale: i64) -> i64 { 159 var row: i64 = 0 160 while row < 7 { 161 var bits: i64 = nx_font_5x7_glyph_row(ch, row) 162 if ch == 95 { if row == 6 { bits = 31 } else { bits = 0 } } 163 if bits < 0 { bits = 0 } 164 var mask: i64 = 16 165 var col: i64 = 0 166 while col < 5 { 167 if (bits / mask) % 2 == 1 { 168 var sy: i64 = 0 169 while sy < scale { var sx: i64 = 0; while sx < scale { r2_px(fb,W,H,x+col*scale+sx,y+row*scale+sy,r,gg,b); sx = sx + 1 } sy = sy + 1 } 170 } 171 mask = mask / 2 172 col = col + 1 173 } 174 row = row + 1 175 } 176 return 0 177} 178// draw a graph node NAME (no trailing .nx) centered at (cx, top y). scale px cell. 179func r2_name(fb: *i64, W: i64, H: i64, g: *EcoGraph, idx: i64, cx: i64, y: i64, r: i64, gg: i64, b: i64, scale: i64) -> i64 { 180 let off: i64 = g.node_off[idx] 181 var n: i64 = 0 182 while g.arena[off+n] != (0 as u8) { n = n + 1 } 183 var e: i64 = n 184 if n > 3 { if g.arena[off+n-3]==(46 as u8) { if g.arena[off+n-2]==(110 as u8) { if g.arena[off+n-1]==(120 as u8) { e = n - 3 } } } } 185 let wpx: i64 = e * 6 * scale 186 var x: i64 = cx - wpx/2 187 var k: i64 = 0 188 while k < e { 189 r2_char(fb,W,H,x,y,g.arena[off+k] as i64,r,gg,b,scale) 190 x = x + 6*scale 191 k = k + 1 192 } 193 return 0 194}