1
2
3\environment evenmorestyle
4
5\useMPlibrary[threesix]
6
7\startcomponent evenmorethreesix
8
9\startchapter[title={ThreeSix, Don Knuths first colorfont?}]
10
11In the process of reaching completion and perfection Don Knuth occasionally posts
12links to upcoming parts of the TAOCP series on his web pages. Now, I admit that
13much is way beyond me but I do understand (and like) the graphics and I know that
14Don uses \METAPOST. The next example code is just a proof of concept but might
15eventually become a decent module (with helpers) for making (runtime) fonts.
16After all, we need to adapt to current developments and \TEX ies always are
17willing to adapt and experiment. This chapter was written at the same time as
18the previous one on \TYPETHREE\ fonts so you might want to read that first.
19
20The font explored here is \type {FONT36}, used in \quotation {A potpourri of
21puzzles} and flagged as \quotation {a special font designed for dissection
22puzzles} (in fascicle 9b for Volume 4). Playing with and visualizing for me often
23works better than formulas, which then distracts me from the original purpose,
24but lets have a closer look anyway.
25
26\startlinecorrection
27 \scale[width=\textwidth]{\DEKFontA 1234567890} \vskip1ex
28 \scale[width=\textwidth]{\DEKFontA ABC{\red DE}FGHIJ{\red K}LM} \vskip1ex
29 \scale[width=\textwidth]{\DEKFontA NOPQRSTUVWXYZ}
30\stoplinecorrection
31
32The font has a fixed maximum height of 8quantities. There is no depth in the
33characters. Some characters are wider. In this example we use a tight bounding
34box. In \CONTEXT\ speak this font is just a regular font but with a special
35feature enabled.
36
37\starttyping
38\definefontfeature
39 [fontthreesix]
40 [default]
41 [metapost=fontthreesix]
42
43\definefont[DEKFontA][Serif*fontthreesix]
44\stoptyping
45
46After this the \type {\DEKFontA} command will set this font as current font. The
47definition mentions \type {Serif} as font name. In \CONTEXT\ this name will
48resolve in the currently defined Serif, so when your document uses Latin Modern
49that will be the one. The \type {fontthreesix} will make this instance use that
50feature set, and the feature definition has the defaults as parent (so we get
51kerning, ligatures, etc.) but as extra feature also \type {metapost}. This means
52that the new glyphs that are about to be defined will actually be injected in the
53\type {Serif}! We will replace characters in that instance. So, the following:
54
55\startbuffer[taocp]
56This font is used in \quotation {The Art Of Computer Programming} by
57Don Knuth, not in volume1, 2 or3, but in number4!
58\stopbuffer
59
60\typebuffer[taocp]
61
62comes out as:
63
64\startnarrower
65\DEKFontA \getbuffer[taocp]
66\stopnarrower
67
68But that doesnt look too good, so we will tweak the font a bit:
69
70\starttyping
71\definefontfeature
72 [fontthreesixcolor]
73 [default]
74 [metapost={category=fontthreesix,spread=.1}]
75
76\definefont[DEKFontD][Serif*fontthreesix]
77\stoptyping
78
79The \type {spread} (multiplied by the font unit, which is 12 basepoints here)
80will add a bit more spacing around the blob:
81
82\startnarrower
83\DEKFontD \getbuffer[taocp]
84\stopnarrower
85
86Now, keep in mind that were talking of a real font here. You can cut and paste
87these characters. Its just the default uppercase Latin alphabet plus digits.
88
89Before we go and look at some of the code needed to render this, a few more
90examples will be given.
91
92\startlinecorrection
93 \scale[width=\textwidth]{\DEKFontB 1234567890} \vskip4pt
94 \scale[width=\textwidth]{\DEKFontB ABCDEFGHIJKLM} \vskip4pt
95 \scale[width=\textwidth]{\DEKFontB NOPQRSTUVWXYZ}
96\stoplinecorrection
97
98In the above example we not only use color, but also a different shape and random
99colors (that is: random per \TEX\ job). The feature definition for this is:
100
101\starttyping
102\definefontfeature
103 [fontthreesixcolor]
104 [default]
105 [metapost={
106 category=fontthreesix,shape=diamond,
107 color=random,pen=fancy,spread=.1
108 }]
109\stoptyping
110
111Possible shapes are \type {circle}, \type {diamond} and \type {square} and
112instead of a random color one can give a known color name. Using transparency
113makes no sense in this font.
114
115A nice usage for this font are initials:
116
117\startbuffer
118\setupinitial[font=Serif*fontthreesixinitial sa 5]
119{\DEKFontB \placeinitial \input zapf\par}
120\stopbuffer
121
122\typebuffer
123
124The initial feature is defined as:
125
126\starttyping
127\definefontfeature
128 [fontthreesixinitial]
129 [metapost={category=fontthreesix,color=random,shape=circle}]
130\stoptyping
131
132We use this in quoting Hermann Zapf, one that for sure is very applicable in
133a case like this:
134
135\startnarrower
136\getbuffer
137\stopnarrower
138
139Some combinations of subfeatures are shown in \in {figure} [threesix:dek]. We
140blow up the diamond with fancy pen example in \in {figure} [threesix:tex]. Alas,
141the \TEX\ logo doesnt look that good in such a font. Using it for acronyms is
142not a good idea anyway, but maybe you can figure out \in {figure}
143[threesix:taocp].
144
145
146
147\definefontfeature
148 [fontthreesixcircle]
149 [metapost={category=fontthreesix,shape=circle,color=random}]
150\definefontfeature
151 [fontthreesixsquare]
152 [metapost={category=fontthreesix,shape=square,color=random}]
153\definefontfeature
154 [fontthreesixdiamond]
155 [metapost={category=fontthreesix,shape=diamond,color=random}]
156\definefontfeature
157 [fontthreesixcirclepen]
158 [metapost={category=fontthreesix,shape=circle,color=random,pen=fancy}]
159\definefontfeature
160 [fontthreesixsquarepen]
161 [metapost={category=fontthreesix,shape=square,color=random,pen=fancy}]
162\definefontfeature
163 [fontthreesixdiamondpen]
164 [metapost={category=fontthreesix,shape=diamond,color=random,pen=fancy}]
165\definefontfeature
166 [fontthreesixcirclerandom]
167 [metapost={category=fontthreesix,random=yes,shape=circle,color=random}]
168\definefontfeature
169 [fontthreesixsquarerandom]
170 [metapost={category=fontthreesix,random=yes,shape=square,color=random}]
171\definefontfeature
172 [fontthreesixdiamondrandom]
173 [metapost={category=fontthreesix,random=yes,shape=diamond,color=random}]
174
175\definefontfeature
176 [fontthreesixcirclerandomspread]
177 [metapost={category=fontthreesix,random=yes,shape=circle,color=random,spread=.1}]
178
179\startplacefigure[reference=threesix:dek]
180 \startcombination[3*3]
181 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixcircle]D\kern1pt E\kern 1ptK}} {\type{shape=circle}}
182 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixsquare]D\kern1pt E\kern 1ptK}} {\type{shape=square}}
183 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixdiamond]D\kern1pt E\kern 1ptK}} {\type{shape=diamond}}
184 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixcirclepen]D\kern1pt E\kern 1ptK}} {\type{shape=circle,pen=fancy}}
185 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixsquarepen]D\kern1pt E\kern 1ptK}} {\type{shape=square,pen=fancy}}
186 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixdiamondpen]D\kern1pt E\kern 1ptK}} {\type{shape=diamond,pen=fancy}}
187 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixcirclerandom]D\kern1pt E\kern 1ptK}} {\type{shape=circle,random=yes}}
188 {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesixsquarerandom]D\kern1pt E\kern 1ptK}} {\type{shape=square,random=yes}}
189 {\scale[width=.3\textwidth]{\definedfont[Serif*fontthreesixdiamondrandom]D\kern1pt E\kern 1ptK}} {\type{shape=diamond,random=yes}}
190 \stopcombination
191\stopplacefigure
192
193\startplacefigure[reference=threesix:tex]
194\scale[width=\textwidth]{\definedfont[Serif*fontthreesixdiamondpen]T\lower.5ex\hbox spread .1em{\hss E\hss}X}
195\stopplacefigure
196
197\startplacefigure[reference=threesix:taocp]
198\scale[width=\textwidth]{\definedfont[Serif*fontthreesixcirclerandomspread]TAOCP}
199\stopplacefigure
200
201You can quit reading now or expose yourself to how this is coded. We use a
202combination of \LUA\ and \METAPOST, but different solutions are possible. The
203shapes are entered (or course) with zeros and ones.
204
205\starttyping
206\startluacode
207local font36 = {
208 ["0"] = "00111100 01111110 11000011 11000011 11000011 ...",
209 ["1"] = "00011100 11111100 11101100 00001100 00001100 ...",
210 .....
211 ["D"] = "11111100 11100010 01100011 01100011 01100011 ...",
212 ["E"] = "1111111 1110001 0110101 0111100 0110100 0110001 ...",
213 .....
214 ["K"] = "11101110 11100100 01101000 01110000 01111000 ...",
215 .....
216}
217\stopluacode
218\stoptyping
219
220We also use \LUA\ to register this font. The actual code looks slightly different
221because it uses some helpers from the \CONTEXT\ \LUA\ libraries. We remap the
222bits pattern onto \METAPOST\ macro calls.
223
224\starttyping
225\startluacode
226local replace = {
227 ["0"] = "N;",
228 ["1"] = "Y;",
229 [" "] = "L;",
230}
231
232function MP.registerthreesix(name)
233 fonts.dropins.registerglyphs {
234 name = name,
235 units = 12,
236 usecolor = true,
237 }
238 for u, v in table.sortedhash(font36) do
239 local ny = 8
240 local nx = (#v - ny + 1) // ny
241 local height = ny * 1.1 - 0.1
242 local width = nx * 1.1 - 0.1
243 local code = string.gsub(v,".",replace)
244 fonts.dropins.registerglyph {
245 category = name,
246 unicode = utf.byte(u),
247 width = width,
248 height = height,
249 code = string.format("ThreeSix(%s);",code),
250 }
251 end
252end
253
254MP.registerthreesix("fontthreesix")
255\stopluacode
256\stoptyping
257
258So, after this the font \type {fontthreesix} is known to the system but we still
259need to provide \METAPOST\ code to generate it. The glyphs themselves are now
260just sequences of \type {N}, \type {Y} and \type {L} with some wrapper code
261around it. The definitions are put in the \type {MP} namespace simply because a
262first version initialized in \METAPOST, and there could create variants, but in
263the end I settled on the parameter interface at the \TEX\ end.
264
265The next definition looks a bit complex but normally such a macro is
266stepwise constructed. Notice how we can query the sub features. In order to make
267that possible the regular \METAFUN\ parameter handling code is used. We just push
268the subfeatures into to \type {mpsfont} namespace.
269
270\starttyping
271\startMPcalculation{simplefun}
272
273def InitializeThreeSix =
274 save Y, N, L, S ; save dx, dy, nx, ny ; save currentpen ;
275 save shape, fillcolor, mypen, random, spread, hoffset ;
276 string shape, fillcolor, mypen ; boolean random ;
277 pen currentpen ;
278 dx := 1110 ;
279 dy := 1110 ;
280 nx := dx ;
281 ny := 0 ;
282 shape := getparameterdefault "mpsfont" "shape" "circle" ;
283 random := hasoption "mpsfont" "random" "true" ;
284 fillcolor := getparameterdefault "mpsfont" "color" "" ;
285 mypen := getparameterdefault "mpsfont" "pen" "" ;
286 spread := getparameterdefault "mpsfont" "spread" 0 ;
287 hoffset := 12 spread 2 ;
288 currentpen := pencircle
289 if mypen = "fancy" :
290 xscaled 120 yscaled 220 rotated 45
291 else :
292 scaled 120
293 fi ;
294 if shape == "square" :
295 def S =
296 unitsquare if random : randomized 110 fi
297 shifted (nx,ny)
298 enddef ;
299 elseif shape = "diamond" :
300 def S =
301 unitdiamond if random : randomized 110 fi
302 shifted (nx,ny)
303 enddef ;
304 else :
305 def S =
306 unitcircle if random : randomizedcontrols 120 fi
307 shifted (nx,ny)
308 enddef ;
309 fi ;
310 def N =
311 nx := nx dx ;
312 draw S ;
313 enddef ;
314 if fillcolor = "random" :
315 def Y =
316 nx := nx dx ;
317 fillup S withcolor white randomized (23,23,23) ;
318 enddef ;
319 elseif fillcolor = "" :
320 def Y =
321 nx := nx dx ;
322 fillup S ;
323 enddef ;
324 else :
325 def Y =
326 nx := nx dx ;
327 fillup S withcolor fillcolor ;
328 enddef ;
329 fi ;
330 def L =
331 nx := dx ;
332 ny := ny dy ;
333 enddef ;
334enddef ;
335
336vardef ThreeSix (text code) =
337 InitializeThreeSix ;
338 draw image (code) shifted (hoffset,ny) ;
339enddef ;
340
341\stopMPcalculation
342\stoptyping
343
344This code is not that efficient in the sense that theres quite some
345\METAPOST\LUA\METAPOST\ traffic going on, for instance each parameter check
346involves this, but in practice performance is quite okay, certainly for such a
347small font. There will be an initializer option some day soon. The \type
348{simplefun} is a reference to an \MPLIB\ instance that does load \METAFUN\ but
349only the modules that make no sense for this kind of usage. It also enforces
350double mode. The calculations wrapper just executes the code and does not place
351some (otherwise empty) graphic.
352
353
354
355
356
357Those who have seen (andor read) \quotation {Concrete Mathematics} will have
358noticed the use of inline images, like dice. Dice are also used in \quotation
359{prefascicle 5a} (I need a few more lives to grasp that, so I stick to the
360images for now!). So, to compensate the somewhat complex code above, I will show
361how to accomplish that. This time we do all in \METAPOST:
362
363\startMPcalculation{simplefun}
364
365def DiceFrame =
366 pickup pencircle scaled 12 ;
367 draw unitsquare scaled 8 ;
368 pickup pencircle scaled 32 ;
369enddef ;
370
371vardef DiceOne =
372 DiceFrame ;
373 draw (4,4) ;
374enddef ;
375vardef DiceTwoA =
376 DiceFrame ;
377 draw (2,6) ; draw (6,2) ;
378enddef ;
379vardef DiceTwoB =
380 DiceFrame ;
381 draw (6,6) ; draw (2,2) ;
382enddef ;
383vardef DiceTwo =
384 if hasoption "mpsfont" "option" "reverse" :
385 DiceTwoB
386 else :
387 DiceTwoA
388 fi ;
389enddef ;
390vardef DiceThreeA =
391 DiceFrame ;
392 draw (2,6) ; draw (4,4) ; draw (6,2) ;
393enddef ;
394vardef DiceThreeB =
395 DiceFrame ;
396 draw (6,6) ; draw (4,4) ; draw (2,2) ;
397enddef ;
398vardef DiceThree =
399 if hasoption "mpsfont" "option" "reverse" :
400 DiceThreeB
401 else :
402 DiceThreeA
403 fi ;
404enddef ;
405vardef DiceFour =
406 DiceFrame ;
407 draw (2,6) ; draw (6,6) ; draw (2,2) ; draw (6,2) ;
408enddef ;
409vardef DiceFive =
410 DiceFrame ;
411 draw (2,6) ; draw (6,6) ; draw (4,4) ; draw (2,2) ; draw (6,2) ;
412enddef ;
413vardef DiceSix =
414 DiceFrame ;
415 draw (2,6) ; draw (6,6) ; draw (2,4) ; draw (6,4) ; draw (2,2) ; draw (6,2) ;
416enddef ;
417
418vardef DiceBad =
419 pickup pencircle scaled 12 ;
420 draw unitsquare scaled 8 ;
421 draw (1,7) -- (7,1) ; draw (1,1) -- (7,7) ;
422enddef ;
423
424lmt_registerglyphs [
425 name = "dice",
426 units = 12,
427 width = 8,
428 height = 8,
429 depth = 0,
430 usecolor = true,
431] ;
432
433lmt_registerglyph [ category = "dice", unicode = "0x2680", code = "DiceOne;" ] ;
434lmt_registerglyph [ category = "dice", unicode = "0x2681", code = "DiceTwo;" ] ;
435lmt_registerglyph [ category = "dice", unicode = "0x2682", code = "DiceThree;" ] ;
436lmt_registerglyph [ category = "dice", unicode = "0x2683", code = "DiceFour;" ] ;
437lmt_registerglyph [ category = "dice", unicode = "0x2684", code = "DiceFive;" ] ;
438lmt_registerglyph [ category = "dice", unicode = "0x2685", code = "DiceSix;" ] ;
439
440lmt_registerglyph [ category = "dice", private = "invaliddice", code = "DiceBad;" ] ;
441
442\stopMPcalculation
443
444This is not that hard to follow. We define some shapes first. These could have
445been assigned to the \type {code} parameter directly but this is nicer. Next we
446register the font itself and after that we set glyphs. We also set the official
447\UNICODE\ slots. So, copying a dice can either result in a digit or in a
448\UNICODE\ slot for a dice. In the example below we switch to a color which
449demonstrates that our dice can be colored at the \TEX\ end. Its either that or
450coloring at the \METAPOST\ end as both demand a different kind of \TYPETHREE\
451embedding trickery.
452
453We actually predefine three features. The digits one will map regular digit in
454the input to dice. We accomplish that via a font feature:
455
456\startbuffer
457\startluacode
458fonts.handlers.otf.addfeature("dice:digits", {
459 type = "substitution",
460 order = { "dice:digits" },
461 nocheck = true,
462 data = {
463 [0x30] = "invaliddice",
464 [0x31] = 0x2680,
465 [0x32] = 0x2681,
466 [0x33] = 0x2682,
467 [0x34] = 0x2683,
468 [0x35] = 0x2684,
469 [0x36] = 0x2685,
470 [0x37] = "invaliddice",
471 [0x38] = "invaliddice",
472 [0x39] = "invaliddice",
473 },
474} )
475\stopluacode
476\stopbuffer
477
478\typebuffer \getbuffer
479
480This kind of trickery is part of the font machinery used in \CONTEXT\ and permits
481runtime adaption of fonts, so we just use the same mechanism. The \type {nocheck}
482is needed to avoid this feature not kicking in due to lack of (at the time of
483checking) yet undefined dice.
484
485\startbuffer
486\definefontfeature
487 [dice:normal]
488 [default]
489 [metapost={category=dice}]
490\definefontfeature
491 [dice:reverse]
492 [default]
493 [metapost={category=dice,option=reverse}]
494\definefontfeature
495 [dice:digits]
496 [dice:digits=yes]
497
498\definefont[DiceN] [Serif*dice:normal]
499\definefont[DiceD] [Serif*dice:normal,dice:digits]
500\definefont[DiceR] [Serif*dice:reverse,dice:digits]
501
502{\DiceD Does 1 it 4 work? And {\darkgreen 3} too?} {\DiceR And how about
503{\darkred 3} then? But 8 should sort of fail!}
504\stopbuffer
505
506\typebuffer \getbuffer
507
508The six digits and \UNICODE\ characters come out the same:
509
510\startbuffer
511\red \DiceD \dostepwiserecurse {1} {6}{1}{\char#1\quad}
512\blue \DiceN \dostepwiserecurse{"2680}{"2685}{1}{\char#1\quad}
513\stopbuffer
514
515\typebuffer
516
517\startlinecorrection
518 \scale[width=\textwidth]{\getbuffer\unskip}
519\stoplinecorrection
520
521It is tempting to implement for instance7 as two dice (a one to multi mapping in
522\OPENTYPE\ speak) but then one has to decide what combination is taken. One can
523also implement ligatures so that for instance 12 results in two six dice. But I
524think thats over the top and only showing \TEX\ muscles. It is anyway not that
525hard to do as we have an interface for that already.
526
527So why not do the dominos as well? Because there are so many dominos we predefine
528the shapes and then register the lot in a loop. We have horizontal and vertical
529variants. Being lazy I just made two helpers while one could have done but with
530some rotation and shifting of the horizontal one. The loop could be a macro but
531we dont save much code that way.
532
533\startbuffer
534\startMPcalculation{simplefun}
535
536picture Dominos[] ;
537
538Dominos[0] := image() ;
539Dominos[1] := image(draw(4,4);) ;
540Dominos[2] := image(draw(2,6);draw(6,2););
541Dominos[3] := image(draw(2,6);draw(4,4);draw(6,2););
542Dominos[4] := image(draw(2,6);draw(6,6);draw(2,2);draw(6,2););
543Dominos[5] := image(draw(2,6);draw(6,6);draw(4,4);draw(2,2);draw(6,2););
544Dominos[6] := image(draw(2,6);draw(4,6);draw(6,6);draw(2,2);draw(4,2);draw(6,2););
545
546lmt_registerglyphs [
547 name = "dominos",
548 units = 12,
549 width = 16,
550 height = 8,
551 depth = 0,
552 usecolor = true,
553] ;
554
555def DrawDominoH(expr a, b) =
556 draw image (
557 pickup pencircle scaled 12 ;
558 if (getparameterdefault "mpsfont" "color" "") = "black" :
559 fillup unitsquare xyscaled (16,8) ;
560 draw (8,.5) -- (8,7.5) withcolor white ;
561 pickup pencircle scaled 32 ;
562 draw Dominos[a]
563 withpen currentpen
564 withcolor white ;
565 draw Dominos[b] shifted (8,0)
566 withpen currentpen
567 withcolor white ;
568 else :
569 draw unitsquare xyscaled (16,8) ;
570 draw (8,0) -- (8,8) ;
571 pickup pencircle scaled 32 ;
572 draw Dominos[a]
573 withpen currentpen ;
574 draw Dominos[b] shifted (8,0)
575 withpen currentpen ;
576 fi ;
577 ) ;
578enddef ;
579
580def DrawDominoV(expr a, b) =
581 draw image (
582 pickup pencircle scaled 12 ;
583 if (getparameterdefault "mpsfont" "color" "") = "black" :
584 fillup unitsquare xyscaled (8,16) ;
585 draw (.5,8) -- (7.5,8) withcolor white ;
586 pickup pencircle scaled 32 ;
587 draw Dominos[a] rotatedaround(center Dominos[a],90)
588 withpen currentpen
589 withcolor white ;
590 draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
591 withpen currentpen
592 withcolor white ;
593 else :
594 draw unitsquare xyscaled (8,16) ;
595 draw (0,8) -- (8,8) ;
596 pickup pencircle scaled 32 ;
597 draw Dominos[a] rotatedaround(center Dominos[a],90)
598 withpen currentpen ;
599 draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
600 withpen currentpen ;
601 fi ;
602 ) ;
603enddef ;
604
605begingroup
606 save unicode ; numeric unicode ; unicode := 127025 ;
607
608 for i=0 upto 6 :
609 for j=0 upto 6 :
610 lmt_registerglyph [
611 category = "dominos",
612 unicode = unicode,
613 code = "DrawDominoH(" & decimal i & "," & decimal j & ");",
614 width = 16,
615 height = 8,
616 ] ;
617 unicode := unicode 1 ;
618 endfor ;
619 endfor ;
620
621 save unicode ; numeric unicode ; unicode := 127075 ;
622
623 for i=0 upto 6 :
624 for j=0 upto 6 :
625 lmt_registerglyph [
626 category = "dominos",
627 unicode = unicode,
628 code = "DrawDominoV(" & decimal i & "," & decimal j & ");",
629 width = 8,
630 height = 16,
631 ] ;
632 unicode := unicode 1 ;
633 endfor ;
634 endfor ;
635endgroup ;
636
637\stopMPcalculation
638\stopbuffer
639
640\typebuffer \getbuffer
641
642Again we predefine a couple of features:
643
644\startbuffer
645\definefontfeature
646 [dominos:white]
647 [default]
648 [metapost={category=dominos}]
649
650\definefontfeature
651 [dominos:black]
652 [default]
653 [metapost={category=dominos,color=black}]
654
655\definefontfeature
656 [dominos:digits]
657 [dominos:digits=yes]
658\stopbuffer
659
660\typebuffer \getbuffer
661
662This last feature is yet to be defined. We could deal with the invalid dominos
663with some substitution trickery but lets keep it simple.
664
665\startbuffer
666\startluacode
667local ligatures = { }
668local unicode = 127025
669
670for i=0x30,0x36 do
671 for j=0x30,0x36 do
672 ligatures[unicode] = { i, j }
673 unicode = unicode + 1 ;
674 end
675end
676
677fonts.handlers.otf.addfeature("dominos:digits", {
678 type = "ligature",
679 order = { "dominos:digits" },
680 nocheck = true,
681 data = ligatures,
682} )
683\stopluacode
684\stopbuffer
685
686\typebuffer \getbuffer
687
688That leaves showing an example. We define a few fonts and again we just extend
689the Serif:
690
691\startbuffer
692\definefont[DominoW][Serif*dominos:white]
693\definefont[DominoB][Serif*dominos:black]
694\definefont[DominoD][Serif*dominos:white,dominos:digits]
695\stopbuffer
696
697\typebuffer \getbuffer
698
699The example is:
700
701\startbuffer
702\DominoW
703 \char"1F043\quad 🀱\quad
704 \char"1F052\quad 🀲\quad
705 \char"1F038\quad 🀳\quad
706 \darkgreen\char"1F049\quad \char"1F07B\quad
707\DominoB
708 \char"1F087\quad
709 \char"1F088\quad
710 \char"1F089\quad
711\DominoD
712 \darkred 12\quad56\quad64
713\stopbuffer
714
715\typebuffer
716
717Watch the ligatures in action:
718
719\startlinecorrection
720 \scale[width=\textwidth]{\getbuffer\unskip}
721\stoplinecorrection
722
723To what extent the usage of symbols like dice and dominos as characters in the
724mentioned book are responsible for them being in \UNICODE, I dont know. Now with
725all these emoji showing up one can wonder about graphics in such a standard
726anyway. But for sure, even after more than three decades, Don still makes nice
727fonts.
728
729A treasure of tiny graphics can be found in \quotation {prefascicle 5c} and many
730are in color! In fact, it has dominos too. It must have been a lot of fun writing
731this! Im thinking of turning the pentominoes into a font where a \type {GPOS}
732feature can deal with the interpentomino kerning (which mighty work out okay
733for example36. The windmill dominos also make a nice example for a font where
734ligatures will boil down to the base form and the (one or more) blades are laid
735over. Its definitely an inspiring read.
736
737\stopchapter
738
739\stoptext
740 |