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}