code wiki / (root) / nx_manga.nx

nx_manga.nx source

↩ module page · 135 lines · 4791 B

1// nx_manga.nx -- WRITING arc, rung W-MANGA-1: the PAGE/PANEL SCRIPT model. 2// Operator intent: "make mangas". A manga script is pages -> panels, each panel a 3// small key:value block (shot / char / say / sfx / caption). This organ counts 4// pages+panels, locates a panel's byte range, validates each panel has the camera 5// "shot" needed to draw it, and EMITS the per-panel image-gen prompt -- feeding the 6// SAME image-gen + companion ingestion the rest of nishi-write already uses. 7// 8// DRY: the per-panel fields are parsed by REUSING nx_scenario's field parser on the 9// panel's byte sub-range (sc_find_field / sc_has / sc_app_field) -- not reimplemented. 10// Pure integer, NO syscalls. The script TEXT is operator/lane DATA (the seam). 11// 12// Script format (PANEL / PAGE are bare marker lines; fields are key:value): 13// PAGE 14// PANEL 15// shot: wide establishing 16// char: Mira, Dev 17// say: We made it. 18// sfx: WHOOSH 19// caption: Dawn over the ruined city. 20// 21// license_tier: ORIGINAL 22// module: nishi-core.write.manga 23// depends: nishi-core.write.scenario 24// capability: WRITE_MANGA_SCRIPT 25import "nx_scenario.nx" 26 27// 1 if the line at i (after optional leading spaces) is exactly the marker tok, 28// i.e. tok followed by a space, newline, or end-of-buffer. 29func mg_line_is(buf: *u8, n: i64, i: i64, tok: *u8) -> i64 { 30 var j: i64 = i 31 var sg: i64 = 1 32 while sg == 1 { 33 if j < n { let c: i64 = buf[j] as i64; if c == 32 { j = j + 1 } else { sg = 0 } } else { sg = 0 } 34 } 35 var m: i64 = 0 36 var okk: i64 = 1 37 var done: i64 = 0 38 while done == 0 { 39 let tc: i64 = tok[m] as i64 40 if tc == 0 { done = 1 } 41 else { 42 if j + m >= n { okk = 0; done = 1 } 43 else { let bc: i64 = buf[j + m] as i64; if bc != tc { okk = 0; done = 1 } else { m = m + 1 } } 44 } 45 } 46 if okk == 1 { 47 if j + m >= n { return 1 } 48 let nc: i64 = buf[j + m] as i64 49 if nc == 32 { return 1 } 50 if nc == 10 { return 1 } 51 return 0 52 } 53 return 0 54} 55 56// count marker lines equal to tok 57func mg_count(buf: *u8, n: i64, tok: *u8) -> i64 { 58 var i: i64 = 0 59 var c: i64 = 0 60 while i < n { 61 if mg_line_is(buf, n, i, tok) == 1 { c = c + 1 } 62 i = sc_next_line(buf, n, i) 63 } 64 return c 65} 66func mg_count_pages(buf: *u8, n: i64) -> i64 { return mg_count(buf, n, "PAGE\x00" as *u8) } 67func mg_count_panels(buf: *u8, n: i64) -> i64 { return mg_count(buf, n, "PANEL\x00" as *u8) } 68 69// byte offset of the idx-th PANEL marker line (0-based), or -1 70func mg_panel_start(buf: *u8, n: i64, idx: i64) -> i64 { 71 var i: i64 = 0 72 var seen: i64 = 0 73 var res: i64 = 0 - 1 74 var go: i64 = 1 75 while go == 1 { 76 if i >= n { go = 0 } 77 else { 78 if mg_line_is(buf, n, i, "PANEL\x00" as *u8) == 1 { 79 if seen == idx { res = i; go = 0 } 80 else { seen = seen + 1; i = sc_next_line(buf, n, i) } 81 } else { i = sc_next_line(buf, n, i) } 82 } 83 } 84 return res 85} 86 87// end of the panel that starts at `start` = next PANEL/PAGE marker, or n 88func mg_panel_end(buf: *u8, n: i64, start: i64) -> i64 { 89 var i: i64 = sc_next_line(buf, n, start) 90 var e: i64 = n 91 var go: i64 = 1 92 while go == 1 { 93 if i >= n { e = n; go = 0 } 94 else { 95 if mg_line_is(buf, n, i, "PANEL\x00" as *u8) == 1 { e = i; go = 0 } 96 else { 97 if mg_line_is(buf, n, i, "PAGE\x00" as *u8) == 1 { e = i; go = 0 } 98 else { i = sc_next_line(buf, n, i) } 99 } 100 } 101 } 102 return e 103} 104 105// completeness: count of panels missing the required "shot" field (0 = drawable) 106func mg_validate(buf: *u8, n: i64) -> i64 { 107 var miss: i64 = 0 108 let np: i64 = mg_count_panels(buf, n) 109 var idx: i64 = 0 110 while idx < np { 111 let s: i64 = mg_panel_start(buf, n, idx) 112 let e: i64 = mg_panel_end(buf, n, s) 113 let sub: *u8 = (buf as i64 + s) as *u8 114 if sc_has(sub, e - s, "shot\x00" as *u8) == 0 { miss = miss + 1 } 115 idx = idx + 1 116 } 117 return miss 118} 119 120// emit the image-gen prompt for panel idx: "<shot>, <char>, <caption>" 121func mg_emit_panel_prompt(buf: *u8, n: i64, idx: i64, out: *u8, cap: i64) -> i64 { 122 let s: i64 = mg_panel_start(buf, n, idx) 123 if s < 0 { out[0] = 0 as u8; return 0 } 124 let e: i64 = mg_panel_end(buf, n, s) 125 let sub: *u8 = (buf as i64 + s) as *u8 126 let sn: i64 = e - s 127 var p: i64 = 0 128 p = sc_app_field(sub, sn, "shot\x00" as *u8, out, p, cap) 129 p = sc_app_lit(out, p, cap, ", \x00" as *u8) 130 p = sc_app_field(sub, sn, "char\x00" as *u8, out, p, cap) 131 p = sc_app_lit(out, p, cap, ", \x00" as *u8) 132 p = sc_app_field(sub, sn, "caption\x00" as *u8, out, p, cap) 133 out[p] = 0 as u8 134 return p 135}