code wiki / _hdl_build / nx_char_scene.nx
nx_char_scene.nx source
↩ module page · 113 lines · 7404 B
1// nx_char_scene.nx -- the DIK-style move done sovereignly: composite a parametric CHARACTER into an ENVIRONMENT
2// as ONE 2D scene still (how Being a DIK etc. ship art -- a posed figure rendered over a background, not layered
3// sprites). Pure integer raster, our own PNG. Renders the character on a chroma-KEY canvas, then blits the
4// non-key (figure) pixels over a generated interior background. HONEST: stylized 2D, our first scene-still rung;
5// not photoreal 3D. license_tier: ORIGINAL expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_shade.nx"
8import "nx_png.nx"
9import "nx_zpng.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 an(v: i64) -> i64 { var m: i64=v; if m==0{sys_write(1,"0" as *u8,1);return 0} let t:*u8=sys_mmap(24); var k:i64=0; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 }
13func frect(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
14 var yy: i64 = y0; if yy < 0 { yy = 0 } var ye: i64 = y1; if ye > h { ye = h }
15 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 }
16 return 0
17}
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 { var x: i64 = cx - rx
21 while x <= cx + rx { let dx: i64 = x-cx; let dy: i64 = y-cy; 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 } } } } } x = x + 1 }
22 y = y + 1 }
23 return 0
24}
25
26// character figure on a chroma-KEY background (no environment), so it can be composited over any scene.
27func portrait_keyed(fb: *i64, W: i64, H: i64, key: i64, skin: i64, hair: i64, hstyle: i64, eyec: i64, outfit: i64, expr: i64) -> i64 {
28 let dark: i64 = sh_rgb(34, 30, 42)
29 sh_clear(fb, W, H, key)
30 efill(fb, W, H, 120, 350, 118, 95, outfit)
31 frect(fb, W, H, 104, 178, 136, 246, skin)
32 efill(fb, W, H, 120, 118, 70, 82, hair)
33 efill(fb, W, H, 64, 122, 9, 15, skin); efill(fb, W, H, 176, 122, 9, 15, skin)
34 efill(fb, W, H, 120, 120, 56, 68, skin)
35 if hstyle == 0 { efill(fb, W, H, 120, 74, 58, 40, hair); frect(fb, W, H, 62, 60, 178, 96, hair) }
36 if hstyle == 1 { efill(fb, W, H, 120, 72, 58, 38, hair); frect(fb, W, H, 120, 60, 180, 104, hair) }
37 if hstyle == 2 { efill(fb, W, H, 120, 70, 56, 30, hair) }
38 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))
39 efill(fb, W, H, 98, 136, 10, 14, eyec); efill(fb, W, H, 142, 136, 10, 14, eyec)
40 efill(fb, W, H, 98, 138, 5, 8, dark); efill(fb, W, H, 142, 138, 5, 8, dark)
41 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))
42 var by: i64 = 112
43 if expr == 1 { by = 108 } if expr == 3 { by = 104 } if expr == 2 { by = 110 }
44 frect(fb, W, H, 85, by, 111, by+4, dark); frect(fb, W, H, 129, by, 155, by+4, dark)
45 if expr == 0 { efill(fb, W, H, 120, 172, 11, 3, sh_rgb(176,92,96)) }
46 if expr == 1 { efill(fb, W, H, 120, 173, 14, 6, sh_rgb(176,92,96)); efill(fb, W, H, 120, 168, 16, 6, skin) }
47 if expr == 2 { efill(fb, W, H, 120, 170, 13, 6, sh_rgb(176,92,96)); efill(fb, W, H, 120, 176, 16, 6, skin) }
48 if expr == 3 { efill(fb, W, H, 120, 176, 6, 8, sh_rgb(92,40,46)) }
49 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))
50 return 0
51}
52
53// warm lamp-room interior background.
54func room_bg(fb: *i64, W: i64, H: i64) -> i64 {
55 var y: i64 = 0
56 while y < H { let t: i64 = y*256/H; let r: i64 = 46 - 22*t/256; let g: i64 = 34 - 16*t/256; let b: i64 = 30 - 14*t/256; frect(fb, W, H, 0, y, W, y+1, sh_rgb(r, g, b)); y = y + 1 }
57 frect(fb, W, H, 0, H*82/100, W, H, sh_rgb(30, 22, 18)) // floor
58 // window (cool, rainy) upper-left
59 frect(fb, W, H, 26, 40, 116, 168, sh_rgb(20, 16, 16)) // frame
60 frect(fb, W, H, 32, 46, 110, 162, sh_rgb(52, 64, 92)) // pane
61 frect(fb, W, H, 70, 46, 73, 162, sh_rgb(20, 16, 16)); frect(fb, W, H, 32, 100, 110, 103, sh_rgb(20, 16, 16)) // muntins
62 var i: i64 = 0
63 while i < 60 { let rx: i64 = 33 + (i*53 + 5) % 76; let ry: i64 = 47 + (i*97 + 3) % 112; var s: i64 = 0; while s < 4 { let px: i64 = rx+s; let py: i64 = ry+s*2; if px < 110 { if py < 162 { fb[py*W+px] = sh_rgb(120,140,175) } } s = s + 1 } i = i + 1 }
64 // warm lamp glow upper-right
65 let gx: i64 = W*82/100; let gy: i64 = 60; let gr: i64 = 70
66 var yy: i64 = gy - gr
67 while yy <= gy + gr { var xx: i64 = gx - gr
68 while xx <= gx + gr { let dx: i64 = xx-gx; let dy: i64 = yy-gy; let d2: i64 = dx*dx + dy*dy
69 if d2 <= gr*gr { if xx>=0 { if xx<W { if yy>=0 { if yy<H {
70 let cur: i64 = fb[yy*W+xx]; let k: i64 = (gr*gr - d2)*90/(gr*gr)
71 var rr: i64 = sh_r(cur)+k; if rr>255 {rr=255} var gg: i64 = sh_g(cur)+k*7/10; if gg>255 {gg=255} var bb: i64 = sh_b(cur)+k/4; if bb>255 {bb=255}
72 fb[yy*W+xx] = sh_rgb(rr,gg,bb) } } } } } xx = xx + 1 }
73 yy = yy + 1 }
74 return 0
75}
76
77// blit non-key pixels of src (CW x CH) onto dst (W x H) at (ox,oy).
78func blit_keyed(dst: *i64, W: i64, H: i64, src: *i64, CW: i64, CH: i64, ox: i64, oy: i64, key: i64) -> i64 {
79 var y: i64 = 0
80 while y < CH { var x: i64 = 0
81 while x < CW { let p: i64 = src[y*CW + x]; if p != key { let dxp: i64 = ox+x; let dyp: i64 = oy+y; if dxp>=0 { if dxp<W { if dyp>=0 { if dyp<H { dst[dyp*W + dxp] = p } } } } } x = x + 1 }
82 y = y + 1 }
83 return 0
84}
85
86func main(argc: i64, argv: *i64) -> i64 {
87 let SW: i64 = 320; let SH: i64 = 380
88 let CW: i64 = 240; let CH: i64 = 320
89 let scene: *i64 = sys_mmap(8*SW*SH) as *i64
90 let cfb: *i64 = sys_mmap(8*CW*CH) as *i64
91 let key: i64 = sh_rgb(255, 0, 255)
92 room_bg(scene, SW, SH)
93 portrait_keyed(cfb, CW, CH, key, sh_rgb(232,200,176), sh_rgb(124,64,42), 1, sh_rgb(72,138,92), sh_rgb(118,52,56), 2) // Mara, WORRIED (fits the scene)
94 blit_keyed(scene, SW, SH, cfb, CW, CH, 40, 60, key)
95 sys_mkdir("knowledge/staging/game" as *u8, 0x1ed)
96 let sz: i64 = write_png_z(scene, SW, SH, "knowledge/staging/game/scene_keeper.png" as *u8)
97 aw("nx_char_scene: keeper scene (Mara, worried) -> scene_keeper.png ("); an(sz); aw(" B compressed)\n" as *u8)
98 // EXPRESSION SHEET: same character, 4 expressions (the morph analog), downscaled 2:1, tiled
99 let SHEETW: i64 = 484; let SHEETH: i64 = 164
100 let sheet: *i64 = sys_mmap(8*SHEETW*SHEETH) as *i64
101 sh_clear(sheet, SHEETW, SHEETH, sh_rgb(28,26,36))
102 var e: i64 = 0
103 while e < 4 {
104 portrait_keyed(cfb, CW, CH, key, sh_rgb(232,200,176), sh_rgb(124,64,42), 1, sh_rgb(72,138,92), sh_rgb(118,52,56), e)
105 let ox: i64 = 2 + e*120
106 var cy: i64 = 0
107 while cy < 160 { var cx: i64 = 0; while cx < 120 { let p: i64 = cfb[(cy*2)*CW + (cx*2)]; if p != key { sheet[(2+cy)*SHEETW + (ox+cx)] = p } cx = cx + 1 } cy = cy + 1 }
108 e = e + 1
109 }
110 write_png_z(sheet, SHEETW, SHEETH, "knowledge/staging/game/expr_sheet.png" as *u8)
111 aw(" expression sheet (neutral/happy/worried/surprised) -> expr_sheet.png\n" as *u8)
112 sys_exit(0); return 0
113}