code wiki / _hdl_build / nx_game_raster.nx

nx_game_raster.nx source

↩ module page · 126 lines · 5501 B

1// nx_game_raster.nx -- LIB: shared INTEGER (no-float) raster primitives for the genre playables. Every 2// flagged open-source genre we build renders its state into the games' packed-RGB framebuffer (R|G<<8|B<<16) 3// through these -- the SAME framebuffer SF5 proved flows through both sovereign display paths (the silicon 4// on-fabric display controller + the x86 UEFI GOP sink). So a genre that renders here IS displayable on 5// sovereign hardware. Pure i64, no float, no canvas. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_font8x8.nx" 8 9func gr_pack(r: i64, g: i64, b: i64) -> i64 { return (r & 0xff) | ((g & 0xff) << 8) | ((b & 0xff) << 16) } 10 11func gr_clear(fb: *i64, w: i64, h: i64, c: i64) -> i64 { 12 let n: i64 = w*h; var i: i64 = 0 13 while i < n { fb[i] = c; i = i + 1 } 14 return 0 15} 16 17func gr_px(fb: *i64, w: i64, h: i64, x: i64, y: i64, c: i64) -> i64 { 18 if x < 0 { return 0 } if y < 0 { return 0 } if x >= w { return 0 } if y >= h { return 0 } 19 fb[y*w + x] = c 20 return 0 21} 22 23func gr_rect(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 { 24 var xs: i64=x0; if xs<0 {xs=0} 25 var ys: i64=y0; if ys<0 {ys=0} 26 var xe: i64=x1; if xe>w {xe=w} 27 var ye: i64=y1; if ye>h {ye=h} 28 var yy: i64=ys 29 while yy<ye { var xx: i64=xs; while xx<xe { fb[yy*w+xx]=c; xx=xx+1 } yy=yy+1 } 30 return 0 31} 32 33// integer filled disc (no float: dx*dx + dy*dy <= rad*rad) -- balls, towers, planets. 34func gr_disc(fb: *i64, w: i64, h: i64, cx: i64, cy: i64, rad: i64, c: i64) -> i64 { 35 var dy: i64 = 0 - rad 36 let r2: i64 = rad*rad 37 while dy <= rad { 38 var dx: i64 = 0 - rad 39 while dx <= rad { 40 if dx*dx + dy*dy <= r2 { gr_px(fb, w, h, cx+dx, cy+dy, c) } 41 dx = dx + 1 42 } 43 dy = dy + 1 44 } 45 return 0 46} 47 48// horizontal + vertical lines (tracks, paths, HUD rules). 49func gr_hline(fb: *i64, w: i64, h: i64, x0: i64, x1: i64, y: i64, c: i64) -> i64 { gr_rect(fb, w, h, x0, y, x1, y+1, c); return 0 } 50func gr_vline(fb: *i64, w: i64, h: i64, x: i64, y0: i64, y1: i64, c: i64) -> i64 { gr_rect(fb, w, h, x, y0, x+1, y1, c); return 0 } 51 52// read back a pixel's green/red channel (gate assertions: "the player cell is green", etc.) 53func gr_r(c: i64) -> i64 { return c & 0xff } 54func gr_g(c: i64) -> i64 { return (c >> 8) & 0xff } 55func gr_b(c: i64) -> i64 { return (c >> 16) & 0xff } 56 57// =================================================================================================== 58// TEXT on the packed-i64 framebuffer (added 2026-07-27, ws=game-interact). 59// ★WHY THIS EXISTS -- it is the ROOT-CAUSE FIX for the long-standing "labels render garbled" bug: 60// nx_gamehud's gh_text/gh_glyph/gh_px index an RGB24 BYTE buffer (`(y*w + x)*3`), but the game screens 61// hand them this framebuffer, where one pixel is an 8-byte i64. Every glyph pixel therefore landed at 62// the wrong byte offset -- horizontally compressed ~2.67x and wrapping into neighbouring rows. The 63// nameplate "solid strip" added earlier treated it as a contrast problem; it was an ADDRESSING problem. 64// (nx_nishi_font_core's nf_draw_text_mem is packed-i64 but its glyph set is only digits + B E H I N O R S W, 65// so it cannot carry real UI text -- hence this, over the full printable-ASCII font8x8 table.) 66// ONE definition, used by every packed-i64 consumer. 67// font8x8 layout: table is 96 glyphs x 8 bytes, index (ch-0x20)*8; byte = one row top->bottom; 68// bit 0 (LSB) = LEFTMOST column. 69// =================================================================================================== 70func gr_glyph(fb: *i64, w: i64, h: i64, ch: i64, x0: i64, y0: i64, c: i64) -> i64 { 71 if ch < 32 { return 0 } 72 if ch > 126 { return 0 } 73 let t: *u8 = font8x8_table() 74 let base: i64 = (ch - 32) * 8 75 var row: i64 = 0 76 while row < 8 { 77 let bits: i64 = t[base + row] as i64 78 var col: i64 = 0 79 while col < 8 { 80 if ((bits >> col) & 1) == 1 { gr_px(fb, w, h, x0 + col, y0 + row, c) } 81 col = col + 1 82 } 83 row = row + 1 84 } 85 return 0 86} 87// draw a NUL-terminated string; returns the x just past the last glyph (proportional advance) 88func gr_text(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, s: *u8, c: i64) -> i64 { 89 let t: *u8 = font8x8_table() 90 var x: i64 = x0 91 var i: i64 = 0 92 while s[i] != (0 as u8) { 93 let ch: i64 = s[i] as i64 94 gr_glyph(fb, w, h, ch, x, y0, c) 95 x = x + font8x8_adv(t, ch) 96 i = i + 1 97 } 98 return x 99} 100// draw a signed integer; returns the x just past the last digit 101func gr_num(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, v: i64, c: i64) -> i64 { 102 let t: *u8 = font8x8_table() 103 var x: i64 = x0 104 var m: i64 = v 105 if m < 0 { gr_glyph(fb, w, h, 45, x, y0, c); x = x + font8x8_adv(t, 45); m = 0 - m } 106 if m == 0 { gr_glyph(fb, w, h, 48, x, y0, c); return x + font8x8_adv(t, 48) } 107 let d: *u8 = sys_mmap(32) as *u8 108 var k: i64 = 0 109 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 110 var j: i64 = 0 111 while j < k { 112 let ch: i64 = d[k - 1 - j] as i64 113 gr_glyph(fb, w, h, ch, x, y0, c) 114 x = x + font8x8_adv(t, ch) 115 j = j + 1 116 } 117 return x 118} 119// pixel width a string will occupy -- lets a caller CENTER text instead of guessing 120func gr_text_w(s: *u8) -> i64 { 121 let t: *u8 = font8x8_table() 122 var wsum: i64 = 0 123 var i: i64 = 0 124 while s[i] != (0 as u8) { wsum = wsum + font8x8_adv(t, s[i] as i64); i = i + 1 } 125 return wsum 126}