code wiki / _hdl_build / nx_char_gen.nx
nx_char_gen.nx source
↩ module page · 73 lines · 4676 B
1// nx_char_gen.nx -- a SOVEREIGN parametric CHARACTER generator (our analog to a DAZ Genesis figure: a character
2// from PARAMETERS, rendered to a 2D portrait by our OWN integer rasterizer -- no DAZ, no third-party, no float).
3// Top VNs (Being a DIK etc.) pose+render reusable 3D figures to 2D stills; this is the first rung of doing that
4// sovereignly: params (skin/hair/hairstyle/eyes/outfit) -> a stylized VN portrait PNG. HONEST: stylized 2D, not
5// photoreal 3D -- but it PROVES a reusable parametric pipeline (same code, different params -> different
6// characters). license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_shade.nx"
9import "nx_png.nx"
10
11func aw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func frect(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
13 var yy: i64 = y0; if yy < 0 { yy = 0 } var ye: i64 = y1; if ye > h { ye = h }
14 while yy < ye { var xx: i64 = x0; if xx < 0 { xx = 0 } var xe: i64 = x1; if xe > w { xe = w } while xx < xe { fb[yy*w + xx] = c; xx = xx + 1 } yy = yy + 1 }
15 return 0
16}
17// filled ellipse centered (cx,cy) radii (rx,ry), color c (integer; rx*rx*ry*ry can be large but fits i64).
18func efill(fb: *i64, w: i64, h: i64, cx: i64, cy: i64, rx: i64, ry: i64, c: i64) -> i64 {
19 var y: i64 = cy - ry
20 while y <= cy + ry {
21 var x: i64 = cx - rx
22 while x <= cx + rx {
23 let dx: i64 = x - cx; let dy: i64 = y - cy
24 if dx*dx*ry*ry + dy*dy*rx*rx <= rx*rx*ry*ry { if x >= 0 { if x < w { if y >= 0 { if y < h { fb[y*w + x] = c } } } } }
25 x = x + 1
26 }
27 y = y + 1
28 }
29 return 0
30}
31
32// render a stylized VN portrait into fb (W x H) from parameters.
33func portrait(fb: *i64, W: i64, H: i64, skin: i64, hair: i64, hstyle: i64, eyec: i64, outfit: i64) -> i64 {
34 let dark: i64 = sh_rgb(34, 30, 42)
35 sh_clear(fb, W, H, sh_rgb(48, 44, 62)) // soft studio bg
36 efill(fb, W, H, 120, 130, 24, 24, sh_rgb(60, 56, 78)) // subtle backdrop disc
37 efill(fb, W, H, 120, 350, 118, 95, outfit) // shoulders / clothing
38 frect(fb, W, H, 104, 178, 136, 246, skin) // neck
39 efill(fb, W, H, 120, 118, 70, 82, hair) // hair (back layer)
40 efill(fb, W, H, 64, 122, 9, 15, skin); efill(fb, W, H, 176, 122, 9, 15, skin) // ears
41 efill(fb, W, H, 120, 120, 56, 68, skin) // head/face
42 // hair front (bangs) -- style varies the silhouette
43 if hstyle == 0 { efill(fb, W, H, 120, 74, 58, 40, hair); frect(fb, W, H, 62, 60, 178, 96, hair) } // straight fringe
44 if hstyle == 1 { efill(fb, W, H, 120, 72, 58, 38, hair); frect(fb, W, H, 120, 60, 180, 104, hair) } // side-swept (covers right)
45 if hstyle == 2 { efill(fb, W, H, 120, 70, 56, 30, hair) } // short
46 // eyes: white, iris, pupil, highlight
47 efill(fb, W, H, 98, 134, 15, 18, sh_rgb(245, 245, 250)); efill(fb, W, H, 142, 134, 15, 18, sh_rgb(245, 245, 250))
48 efill(fb, W, H, 98, 136, 10, 14, eyec); efill(fb, W, H, 142, 136, 10, 14, eyec)
49 efill(fb, W, H, 98, 138, 5, 8, dark); efill(fb, W, H, 142, 138, 5, 8, dark)
50 efill(fb, W, H, 95, 130, 3, 4, sh_rgb(255, 255, 255)); efill(fb, W, H, 139, 130, 3, 4, sh_rgb(255, 255, 255))
51 // brows
52 frect(fb, W, H, 85, 112, 111, 116, dark); frect(fb, W, H, 129, 112, 155, 116, dark)
53 // nose hint + mouth
54 efill(fb, W, H, 120, 158, 3, 5, sh_rgb(sh_r(skin)*8/10, sh_g(skin)*8/10, sh_b(skin)*8/10))
55 efill(fb, W, H, 120, 172, 11, 4, sh_rgb(176, 92, 96))
56 // blush
57 efill(fb, W, H, 92, 158, 9, 5, sh_rgb(232, 150, 150)); efill(fb, W, H, 148, 158, 9, 5, sh_rgb(232, 150, 150))
58 return 0
59}
60
61func main(argc: i64, argv: *i64) -> i64 {
62 let W: i64 = 240; let H: i64 = 320
63 let fb: *i64 = sys_mmap(8*W*H) as *i64
64 sys_mkdir("knowledge/staging/game" as *u8, 0x1ed)
65 // Char A -- "Mara" the keeper: auburn side-swept hair, green eyes, fair weathered skin, maroon coat
66 portrait(fb, W, H, sh_rgb(232, 200, 176), sh_rgb(124, 64, 42), 1, sh_rgb(72, 138, 92), sh_rgb(118, 52, 56))
67 write_png(fb, W, H, "knowledge/staging/game/char_mara.png" as *u8)
68 // Char B -- a different person from the SAME code, different params (proves the parametric pipeline)
69 portrait(fb, W, H, sh_rgb(206, 162, 132), sh_rgb(222, 192, 110), 0, sh_rgb(70, 112, 184), sh_rgb(54, 64, 104))
70 write_png(fb, W, H, "knowledge/staging/game/char_2.png" as *u8)
71 aw("nx_char_gen: 2 parametric portraits -> knowledge/staging/game/char_mara.png, char_2.png (integer raster, sovereign PNG)\n" as *u8)
72 sys_exit(0); return 0
73}