code wiki / _hdl_build / nx_game_art.nx
nx_game_art.nx source
↩ module page · 87 lines · 3926 B
1// nx_game_art.nx -- shared RICH-render primitives, the answer to nx_game_critic's TOY verdict. The games
2// scored TOY (120) because they draw flat discs on a near-empty starfield: palette ~10, gradient 0,
3// coverage ~180. These primitives lift all three axes: 2D gradient nebulas (palette+gradient+coverage),
4// radial-falloff glow orbs (gradient+detail), star dust (palette), gradient meters (gradient). ONE
5// definition, used by nx_frontier_engine, nx_drift_engine, and the critic's reference frame -- OO
6// consolidation of the look, so improving the art improves every game at once. LIB. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_game_raster.nx"
9const K_MAGIC_2654435761: i64 = 2654435761
10const K_MAGIC_40503: i64 = 40503
11
12func art_clampb(v: i64) -> i64 { if v<0 { return 0 } if v>255 { return 255 } return v }
13
14// 2D gradient nebula background with per-pixel texture: colour ramps top->bottom AND left->right, plus a
15// cheap deterministic noise so no two pixels are identical (kills the flat-fill palette collapse).
16func art_nebula(fb: *i64, w: i64, h: i64, r0: i64, g0: i64, b0: i64, r1: i64, g1: i64, b1: i64) -> i64 {
17 var y: i64=0
18 while y<h {
19 var x: i64=0
20 while x<w {
21 let ty: i64 = y*256/h
22 let tx: i64 = x*256/w
23 let nz: i64 = ((x*13 + y*7 + (x/5)*(y/9)) % 15) - 7
24 let rr: i64 = art_clampb(r0 + (r1-r0)*ty/256 + (r1-r0)*tx/768 + nz)
25 let gg: i64 = art_clampb(g0 + (g1-g0)*ty/256 + (g1-g0)*tx/768 + nz)
26 let bb: i64 = art_clampb(b0 + (b1-b0)*ty/256 + (b1-b0)*tx/768 + nz)
27 fb[y*w+x] = gr_pack(rr,gg,bb)
28 x=x+1
29 }
30 y=y+1
31 }
32 return 0
33}
34
35// varied-brightness star dust (adds palette + fine detail without flattening)
36func art_stardust(fb: *i64, w: i64, h: i64, count: i64) -> i64 {
37 var s: i64=0
38 while s<count {
39 var px: i64 = (s*K_MAGIC_2654435761)%w
40 if px<0 { px=0-px }
41 var py: i64 = (s*K_MAGIC_40503+17)%(h-40)
42 if py<0 { py=0-py }
43 let b: i64 = 40 + (s*37)%150
44 gr_px(fb, w, h, px%w, py, gr_pack(b, b, art_clampb(b+25)))
45 if (s%5)==0 { gr_px(fb, w, h, (px+1)%w, py, gr_pack(b*3/4, b*3/4, b)) }
46 s=s+1
47 }
48 return 0
49}
50
51// a glowing orb: concentric discs with a smooth radial falloff (bright core -> dim halo) + a lit rim.
52// This is the single biggest lever from flat discs -> RICH: it fills a gradient where a flat disc had one colour.
53func art_glow_orb(fb: *i64, w: i64, h: i64, cx: i64, cy: i64, rad: i64, cr: i64, cg: i64, cb: i64) -> i64 {
54 // outer halo (dim, large)
55 var r: i64 = rad+rad/2
56 while r>rad {
57 let k: i64 = (r-rad)*220/(rad/2+1)
58 gr_disc(fb, w, h, cx, cy, r, gr_pack(art_clampb(cr*(60-k/4)/200), art_clampb(cg*(60-k/4)/200), art_clampb(cb*(70-k/4)/200)))
59 r=r-1
60 }
61 // body: bright core fading to edge
62 r = rad
63 while r>=1 {
64 let k: i64 = r*256/rad
65 gr_disc(fb, w, h, cx, cy, r, gr_pack(art_clampb(cr*(320-k)/300), art_clampb(cg*(320-k)/300), art_clampb(cb*(320-k)/300)))
66 r=r-1
67 }
68 // hot core + a specular pip offset up-left (a lit sphere read)
69 gr_disc(fb, w, h, cx, cy, rad/4, gr_pack(250,250,255))
70 gr_disc(fb, w, h, cx-rad/3, cy-rad/3, rad/7+1, gr_pack(255,255,255))
71 return 0
72}
73
74// a gradient-filled meter (many shades across its length) -- replaces the flat-colour HUD bar
75func art_meter(fb: *i64, w: i64, h: i64, x: i64, y: i64, len: i64, ht: i64, filled: i64, r0: i64, g0: i64, b0: i64, r1: i64, g1: i64, b1: i64) -> i64 {
76 // track
77 gr_rect(fb, w, h, x, y, x+len, y+ht, gr_pack(26,24,42))
78 var i: i64=0
79 while i<filled {
80 if i<len {
81 let t: i64 = i*256/(len)
82 gr_rect(fb, w, h, x+i, y, x+i+1, y+ht, gr_pack(art_clampb(r0+(r1-r0)*t/256), art_clampb(g0+(g1-g0)*t/256), art_clampb(b0+(b1-b0)*t/256)))
83 }
84 i=i+1
85 }
86 return 0
87}