code wiki / _hdl_build / nx_font_family_gate.nx

nx_font_family_gate.nx source

↩ module page · 298 lines · 16519 B

1// nx_font_family_gate.nx -- THE FONT GENERATOR proof: ONE glyph program + a knob vector => DIFFERENT fonts 2// (operator: "turn it into something where we can generate different types of fonts... this one font is our 3// pioneer benchmark"). Generates a 4-variant FAMILY from font_spec knobs -- Light(W95) / Regular(pioneer 4// defaults) / Bold(W175) / Soft(2-pass Chaikin + round caps) -- renders the same specimen through the SAME 5// engine, and proves the generator claims MECHANICALLY: 6// T1 all variants render real ink; 7// T2 the weight knob ACTS + ordering holds: ink(Light) < ink(Regular) < ink(Bold), Bold >= Light*115%; 8// T3 ★THE PARAMETRIC INVARIANT: baseline bounce stays professional-flat (<=15 permille) for EVERY variant 9// -- the metric lines are f(W), so alignment survives knob changes BY CONSTRUCTION (this is what makes 10// it a GENERATOR, not one hand-tuned font); 11// T4 style knobs ACT: Soft differs from Regular by real pixels; 12// T5 determinism liar-kill: Regular rendered twice is BYTE-IDENTICAL (so T2's ordering is signal not noise); 13// T6 family specimen sheet written (evidence to eyeball). 14// license_tier: ORIGINAL expect_exit: 0 15import "nx_font.nx" 16import "nx_aa_raster.nx" 17import "nx_png_write.nx" 18 19func fg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 20func fg_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 21func fg_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 22 23const FG_W: i64 = 1250 24const FG_H: i64 = 220 25const FG_PX: i64 = 150 // specimen em size (letter height ~80px so 1px of the 26 // measurement grid = ~12.5 permille -- FINER than the 27 // 15-permille bar; at 110px, 1px was 17 permille and the 28 // bar was finer than the ruler = quantization false-fails) 29 30// render the specimen through the REAL engine into an RGB buffer (white bg, dark ink) 31func fam_render(text: *u8, rgb: *u8) -> i64 { 32 let n: i64 = fg_slen(text) 33 let ss: i64 = 3 34 let S: i64 = FG_PX * ss 35 let xs: *i64 = sys_mmap(8*300000) as *i64 36 let ys: *i64 = sys_mmap(8*300000) as *i64 37 let cstart: *i64 = sys_mmap(8*30000) as *i64 38 let clen: *i64 = sys_mmap(8*30000) as *i64 39 let np: *i64 = sys_mmap(16) as *i64; np[0]=0 40 let nc: *i64 = sys_mmap(16) as *i64; nc[0]=0 41 let cs: *i64 = sys_mmap(8*20) as *i64 42 let sn: *i64 = sys_mmap(8*20) as *i64 43 font_trig_init(cs, sn) 44 font_text(text, n, xs, ys, cstart, clen, np, nc, cs, sn, 16*ss, 8*ss, S) 45 let cov: *u8 = sys_mmap(FG_W*FG_H + 16) 46 var z: i64 = 0 47 while z < FG_W*FG_H { cov[z]=0 as u8; z=z+1 } 48 aa_render(xs, ys, cstart, clen, nc[0], cov, FG_W, FG_H, ss) 49 var i: i64 = 0 50 while i < FG_W*FG_H*3 { rgb[i]=255 as u8; i=i+1 } 51 aa_blit(rgb, FG_W, FG_H, 0, 0, cov, FG_W, FG_H, 24, 26, 38) 52 return 0 53} 54func fam_lum(rgb: *u8, o: i64) -> i64 { return (2126*(rgb[o] as i64)+7152*(rgb[o+1] as i64)+722*(rgb[o+2] as i64))/10000 } 55func fam_ink(rgb: *u8) -> i64 { 56 var ink: i64=0 57 var p: i64=0 58 while p < FG_W*FG_H { if fam_lum(rgb,p*3) < 128 { ink=ink+1 } p=p+1 } 59 return ink 60} 61func fam_isqrt(n: i64) -> i64 { if n<=0 { return 0 } var x: i64=n; var y: i64=(x+1)/2; while y<x { x=y; y=(x+n/x)/2 } return x } 62// baseline bounce (permille of letter height): segment letters by white columns, std of letter-bottoms 63func fam_bounce(rgb: *u8) -> i64 { 64 let colink: *i64 = sys_mmap(8*(FG_W+4)) as *i64 65 let colbot: *i64 = sys_mmap(8*(FG_W+4)) as *i64 66 let coltop: *i64 = sys_mmap(8*(FG_W+4)) as *i64 67 var x: i64=0 68 while x<FG_W { 69 var has: i64=0; var bot: i64=0-1; var top: i64=FG_H 70 var y: i64=0 71 while y<FG_H { if fam_lum(rgb,(y*FG_W+x)*3) < 128 { has=1; if y>bot { bot=y }; if y<top { top=y } } y=y+1 } 72 colink[x]=has; colbot[x]=bot; coltop[x]=top 73 x=x+1 74 } 75 let bots: *i64 = sys_mmap(8*128) as *i64 76 let hts: *i64 = sys_mmap(8*128) as *i64 77 var nl: i64=0 78 var inrun: i64=0 79 var rb: i64=0-1 80 var rt: i64=FG_H 81 var gap: i64=0 82 x=0 83 while x<FG_W { 84 if colink[x]==1 { 85 if inrun==0 { inrun=1; rb=0-1; rt=FG_H } 86 if colbot[x]>rb { rb=colbot[x] } 87 if coltop[x]<rt { rt=coltop[x] } 88 gap=0 89 } else { if inrun==1 { gap=gap+1; if gap>=4 { if nl<128 { bots[nl]=rb; hts[nl]=rb-rt; nl=nl+1 } inrun=0 } } } 90 x=x+1 91 } 92 if inrun==1 { if nl<128 { bots[nl]=rb; hts[nl]=rb-rt; nl=nl+1 } } 93 if nl<4 { return 0 - 1 } 94 var sb: i64=0; var sh: i64=0 95 var i: i64=0 96 while i<nl { sb=sb+bots[i]; sh=sh+hts[i]; i=i+1 } 97 let mb: i64=sb/nl 98 let mh: i64=sh/nl 99 var vs: i64=0 100 i=0 101 while i<nl { let dd: i64=bots[i]-mb; vs=vs+dd*dd; i=i+1 } 102 if mh<=0 { return 0 - 1 } 103 return (fam_isqrt(vs/nl)*1000)/mh 104} 105// stroke-width UNIFORMITY: CV (stddev/mean, permille) of horizontal dark-run widths (stroke crossings, 2..40px). 106// Machine-regular MONOLINE -> low CV (all strokes the pen width); organic modulated/swelled -> high CV. 107func fam_isqrt2(n: i64) -> i64 { if n<=0 { return 0 } var x: i64=n; var y: i64=(x+1)/2; while y<x { x=y; y=(x+n/x)/2 } return x } 108func fam_stroke_cv(rgb: *u8) -> i64 { 109 // find the ink band, then scan ONLY the mid-x-height rows (35..55% down) where strokes are VERTICAL -- 110 // there a horizontal run == a stroke width, uncounfounded by the wide arcs at bowl tops/bottoms. 111 var miny: i64=FG_H 112 var maxy: i64=0 113 var yy: i64=0 114 while yy<FG_H { var xx: i64=0; var has: i64=0; while xx<FG_W { if fam_lum(rgb,(yy*FG_W+xx)*3)<128 { has=1; xx=FG_W } else { xx=xx+1 } } if has==1 { if yy<miny{miny=yy} ; if yy>maxy{maxy=yy} } yy=yy+1 } 115 let h: i64 = maxy-miny 116 if h<10 { return 0 } 117 let y0: i64 = miny + (h*35)/100 118 let y1: i64 = miny + (h*55)/100 119 var runs: i64=0 120 var sumw: i64=0 121 let wtab: *i64 = sys_mmap(8*20000) as *i64 122 var y: i64=y0 123 while y <= y1 { 124 var x: i64=0 125 var cur: i64=0 126 while x < FG_W { 127 if fam_lum(rgb,(y*FG_W+x)*3) < 128 { cur=cur+1 } 128 else { if cur>0 { if cur>=2 { if cur<=40 { if runs<20000 { wtab[runs]=cur; runs=runs+1; sumw=sumw+cur } } } cur=0 } } 129 x=x+1 130 } 131 y=y+1 132 } 133 if runs<20 { return 0 } 134 let mean: i64 = sumw/runs 135 if mean<=0 { return 0 } 136 var vs: i64=0 137 var i: i64=0 138 while i<runs { let dd: i64=wtab[i]-mean; vs=vs+dd*dd; i=i+1 } 139 return (fam_isqrt2(vs/runs)*1000)/mean 140} 141// ink WIDTH (rightmost - leftmost inked column) -- for the WIDTH axis: condensed < normal < extended. 142func fam_inkw(rgb: *u8) -> i64 { 143 var lo: i64 = FG_W 144 var hi: i64 = 0 145 var y: i64 = 0 146 while y < FG_H { 147 var x: i64 = 0 148 while x < FG_W { if fam_lum(rgb,(y*FG_W+x)*3) < 128 { if x<lo {lo=x} ; if x>hi {hi=x} } x=x+1 } 149 y=y+1 150 } 151 if hi < lo { return 0 } 152 return hi - lo 153} 154func fam_diff(a: *u8, b: *u8) -> i64 { 155 var d: i64=0 156 var p: i64=0 157 while p < FG_W*FG_H { var da: i64=(a[p*3] as i64)-(b[p*3] as i64); if da<0 { da=0-da } if da>30 { d=d+1 } p=p+1 } 158 return d 159} 160 161func main() -> i64 { 162 fg_puts("=== nx_font_family_gate -- ONE glyph program + knobs = a FONT FAMILY (the generator proof) ===\n" as *u8) 163 let spec: *u8 = "consensus 037\x00" as *u8 164 let rgbL: *u8 = sys_mmap(FG_W*FG_H*3+64) 165 let rgbR: *u8 = sys_mmap(FG_W*FG_H*3+64) 166 let rgbR2: *u8 = sys_mmap(FG_W*FG_H*3+64) 167 let rgbB: *u8 = sys_mmap(FG_W*FG_H*3+64) 168 let rgbS: *u8 = sys_mmap(FG_W*FG_H*3+64) 169 170 font_spec(95, 0, 0, 0) // LIGHT 171 fam_render(spec, rgbL) 172 font_spec_reset() // REGULAR = the pioneer defaults 173 fam_render(spec, rgbR) 174 fam_render(spec, rgbR2) // determinism twin 175 font_spec(160, 0, 0, 0) // BOLD (W=160 = the validated top of the wght range: 176 fam_render(spec, rgbB) // above ~160 the e/s interior clearances (~190em gaps 177 // minus the pen) CLOG -- opening heavy-weight apertures 178 // is per-glyph bold-master craft = a named next axis) 179 font_spec(132, 12, 1, 1) // SOFT (round caps; 1-pass -- ⚠passes=2 lifts curve 180 fam_render(spec, rgbS) // extrema ~8em (Chaikin shrinkage) = breaks the baseline 181 // invariant -> knob CONSTRAINED until extremum-compensated 182 let rgbO: *u8 = sys_mmap(FG_W*FG_H*3+64) 183 font_spec_reset() 184 font_spec_slant(18) // OBLIQUE (~10deg, the slnt axis; sheared about the baseline) 185 fam_render(spec, rgbO) 186 let rgbG: *u8 = sys_mmap(FG_W*FG_H*3+64) 187 font_spec_reset() 188 font_spec_geo(1); font_spec_mod(100); font_spec_swell(100) // GEOMETRIC (machine-regular, monoline) 189 fam_render(spec, rgbG) 190 let rgbGC: *u8 = sys_mmap(FG_W*FG_H*3+64) // geometric CONDENSED (wdth 78) 191 font_spec_reset(); font_spec_geo(1); font_spec_mod(100); font_spec_swell(100); font_spec_wdth(78) 192 fam_render(spec, rgbGC) 193 let rgbGE: *u8 = sys_mmap(FG_W*FG_H*3+64) // geometric EXTENDED (wdth 128) 194 font_spec_reset(); font_spec_geo(1); font_spec_mod(100); font_spec_swell(100); font_spec_wdth(128) 195 fam_render(spec, rgbGE) 196 font_spec_reset() 197 198 let inkL: i64 = fam_ink(rgbL) 199 let inkR: i64 = fam_ink(rgbR) 200 let inkB: i64 = fam_ink(rgbB) 201 let bL: i64 = fam_bounce(rgbL) 202 let bR: i64 = fam_bounce(rgbR) 203 let bB: i64 = fam_bounce(rgbB) 204 let bS: i64 = fam_bounce(rgbS) 205 let dRS: i64 = fam_diff(rgbR, rgbS) 206 let dRR: i64 = fam_diff(rgbR, rgbR2) 207 let inkS: i64 = fam_ink(rgbS) 208 let inkO: i64 = fam_ink(rgbO) 209 let bO: i64 = fam_bounce(rgbO) 210 let dRO: i64 = fam_diff(rgbR, rgbO) 211 let inkG: i64 = fam_ink(rgbG) 212 let bG: i64 = fam_bounce(rgbG) 213 let cvR: i64 = fam_stroke_cv(rgbR) 214 let cvG: i64 = fam_stroke_cv(rgbG) 215 fg_puts(" ink: Light=" as *u8); fg_num(inkL); fg_puts(" Regular=" as *u8); fg_num(inkR); fg_puts(" Bold=" as *u8); fg_num(inkB); fg_puts("\n" as *u8) 216 fg_puts(" bounce permille: L=" as *u8); fg_num(bL); fg_puts(" R=" as *u8); fg_num(bR); fg_puts(" B=" as *u8); fg_num(bB); fg_puts(" Soft=" as *u8); fg_num(bS); fg_puts("\n" as *u8) 217 fg_puts(" diff px: Regular-vs-Soft=" as *u8); fg_num(dRS); fg_puts(" Regular-vs-Regular=" as *u8); fg_num(dRR); fg_puts("\n" as *u8) 218 219 var pass: i64=0 220 var ttl: i64=0 221 ttl=ttl+1; fg_puts(" T1 all variants render real ink (>5000 px each): " as *u8) 222 if inkL>5000 { if inkR>5000 { if inkB>5000 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) } 223 ttl=ttl+1; fg_puts(" T2 weight knob acts + orders (L<R<B, B>=L*115%): " as *u8) 224 if inkL<inkR { if inkR<inkB { if inkB*100 >= inkL*115 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) } 225 ttl=ttl+1; fg_puts(" T3 PARAMETRIC INVARIANT: butt variants dead-flat (<=15 permille) + round-cap Soft within its\n" as *u8) 226 fg_puts(" geometric tolerance (<=25: a round cap on a DIAGONAL end extends (1-cos)*r below the line -- a\n" as *u8) 227 fg_puts(" property of the style, not misalignment): " as *u8) 228 var flat: i64=1 229 if bL<0 { flat=0 } ; if bL>15 { flat=0 } 230 if bR<0 { flat=0 } ; if bR>15 { flat=0 } 231 if bB<0 { flat=0 } ; if bB>15 { flat=0 } 232 if bS<0 { flat=0 } ; if bS>25 { flat=0 } 233 if flat==1 { pass=pass+1; fg_puts("PASS (alignment survives every knob = a GENERATOR, not one font)\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 234 ttl=ttl+1; fg_puts(" T4 style knobs act (Soft differs from Regular >800 px -- the end-cap discs): " as *u8) 235 if dRS>800 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 236 ttl=ttl+1; fg_puts(" T5 determinism liar-kill (Regular twice = 0 diff px): " as *u8) 237 if dRR==0 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 238 ttl=ttl+1; fg_puts(" T5b NO-HOLES guard: Soft ink >= Regular ink (round caps only ADD; winding cancellation SUBTRACTS -- the candy-cane bug's mechanical witness): " as *u8) 239 if inkS >= inkR { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL (ink " as *u8); fg_num(inkS); fg_puts(" < " as *u8); fg_num(inkR); fg_puts(")\n" as *u8) } 240 ttl=ttl+1; fg_puts(" T5c OBLIQUE invariants: shear about the baseline preserves FLATNESS (bounce " as *u8); fg_num(bO); fg_puts(" <=15) and AREA (ink " as *u8); fg_num(inkO); fg_puts(" within 4% of Regular " as *u8); fg_num(inkR); fg_puts("), and it ACTS (diff " as *u8); fg_num(dRO); fg_puts(" >2000): " as *u8) 241 var okO: i64 = 1 242 if bO < 0 { okO = 0 } ; if bO > 15 { okO = 0 } 243 var dInk: i64 = inkO - inkR 244 if dInk < 0 { dInk = 0 - dInk } 245 if dInk * 25 > inkR { okO = 0 } 246 if dRO <= 2000 { okO = 0 } 247 if okO == 1 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 248 let dRG: i64 = fam_diff(rgbR, rgbG) 249 ttl=ttl+1; fg_puts(" T5d GEOMETRIC (machine-regular) variant renders (ink " as *u8); fg_num(inkG); fg_puts("), baseline flat (" as *u8); fg_num(bG); fg_puts("<=15), DISTINCT letterforms vs organic (diff " as *u8); fg_num(dRG); fg_puts(" >8000 -- exact-circle bowls, not hand curves): " as *u8) 250 // NOTE: machine regularity here is BY CONSTRUCTION (every bowl = the SAME fe_ring circle, every arch = the 251 // same geo_arc) -- provable in the code, not by a pixel metric (stroke-CV is confounded: circles have varied 252 // cross-sections in any scan direction). Legibility is measured separately: geo_specimen OCR = 9/9 pangram. 253 var okG: i64 = 1 254 if inkG < 5000 { okG = 0 } 255 if bG < 0 { okG = 0 } ; if bG > 15 { okG = 0 } 256 if dRG < 8000 { okG = 0 } 257 if okG == 1 { pass=pass+1; fg_puts("PASS (machine-regular geometric = a real emitted TYPE)\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 258 let wGC: i64 = fam_inkw(rgbGC) 259 let wGN: i64 = fam_inkw(rgbG) 260 let wGE: i64 = fam_inkw(rgbGE) 261 ttl=ttl+1; fg_puts(" T5e WIDTH axis ACTS (condense/extend, stems keep weight): inkw condensed=" as *u8); fg_num(wGC); fg_puts(" < normal=" as *u8); fg_num(wGN); fg_puts(" < extended=" as *u8); fg_num(wGE); fg_puts(": " as *u8) 262 var okWx: i64 = 1 263 if wGC >= wGN { okWx = 0 } 264 if wGN >= wGE { okWx = 0 } 265 if okWx == 1 { pass=pass+1; fg_puts("PASS (VARIATION -- a real wdth axis)\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 266 267 // family specimen sheet: 6 rows (Light / Regular / Bold / Soft / Oblique / Geometric) 268 let SH2: i64 = FG_H*6 269 let sheet: *u8 = sys_mmap(FG_W*SH2*3+64) 270 var q: i64=0 271 while q<FG_W*SH2*3 { sheet[q]=255 as u8; q=q+1 } 272 var row: i64=0 273 while row<6 { 274 var src: *u8 = rgbL 275 if row==1 { src=rgbR } 276 if row==2 { src=rgbB } 277 if row==3 { src=rgbS } 278 if row==4 { src=rgbO } 279 if row==5 { src=rgbG } 280 var y: i64=0 281 while y<FG_H { 282 var x2: i64=0 283 while x2<FG_W*3 { sheet[((row*FG_H+y)*FG_W)*3+x2] = src[(y*FG_W)*3+x2]; x2=x2+1 } 284 y=y+1 285 } 286 row=row+1 287 } 288 nx_png_write_rgb("knowledge/status/font_family_sheet.png\x00" as *u8, sheet, FG_W, SH2) 289 let lp: *i64 = sys_mmap(16) as *i64 290 lp[0]=0-1 291 sys_read_file("knowledge/status/font_family_sheet.png\x00" as *u8, lp) 292 ttl=ttl+1; fg_puts(" T6 family sheet written (" as *u8); fg_num(lp[0]); fg_puts("B): " as *u8) 293 if lp[0]>20000 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } 294 295 fg_puts("FONT-FAMILY-GATE passed " as *u8); fg_num(pass); fg_puts("/" as *u8); fg_num(ttl) 296 if pass==ttl { fg_puts(" verdict=GREEN (Light/Regular/Bold/Soft from ONE program -- see font_family_sheet.png)\n" as *u8); sys_exit(0); return 0 } 297 fg_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 298}