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}