summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/evenmore/evenmore-threesix.tex
blob: d75f9b68396f948667707c9db5b5d78837735d3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
% language=us

\environment evenmore-style

\useMPlibrary[threesix]

\startcomponent evenmore-threesix

\startchapter[title={ThreeSix, Don Knuths first colorfont?}]

In the process of reaching completion and perfection Don Knuth occasionally posts
links to upcoming parts of the TAOCP series on his web pages. Now, I admit that
much is way beyond me but I do understand (and like) the graphics and I know that
Don uses \METAPOST. The next example code is just a proof of concept but might
eventually become a decent module (with helpers) for making (runtime) fonts.
After all, we need to adapt to current developments and \TEX ies always are
willing to adapt and experiment. This chapter was written at the same time as
the previous one on \TYPETHREE\ fonts so you might want to read that first.

The font explored here is \type {FONT36}, used in \quotation {A potpourri of
puzzles} and flagged as \quotation {a special font designed for dissection
puzzles} (in fascicle 9b for Volume 4). Playing with and visualizing for me often
works better than formulas, which then distracts me from the original purpose,
but let's have a closer look anyway.

\startlinecorrection
    \scale[width=\textwidth]{\DEKFontA 1234567890} \vskip1ex
    \scale[width=\textwidth]{\DEKFontA ABC{\red DE}FGHIJ{\red K}LM} \vskip1ex
    \scale[width=\textwidth]{\DEKFontA NOPQRSTUVWXYZ}
\stoplinecorrection

The font has a fixed maximum height of 8~quantities. There is no depth in the
characters. Some characters are wider. In this example we use a tight bounding
box. In \CONTEXT\ speak this font is just a regular font but with a special
feature enabled.

\starttyping
\definefontfeature
  [fontthreesix]
  [default]
  [metapost=fontthreesix]

\definefont[DEKFontA][Serif*fontthreesix]
\stoptyping

After this the \type {\DEKFontA} command will set this font as current font. The
definition mentions \type {Serif} as font name. In \CONTEXT\ this name will
resolve in the currently defined Serif, so when your document uses Latin Modern
that will be the one. The \type {fontthreesix} will make this instance use that
feature set, and the feature definition has the defaults as parent (so we get
kerning, ligatures, etc.) but as extra feature also \type {metapost}. This means
that the new glyphs that are about to be defined will actually be injected in the
\type {Serif}! We will replace characters in that instance. So, the following:

\startbuffer[taocp]
This font is used in \quotation {The Art Of Computer Programming} by
Don Knuth, not in volume~1, 2 or~3, but in number~4!
\stopbuffer

\typebuffer[taocp]

comes out as:

\startnarrower
\DEKFontA \getbuffer[taocp]
\stopnarrower

But that doesn't look too good, so we will tweak the font a bit:

\starttyping
\definefontfeature
  [fontthreesix-color]
  [default]
  [metapost={category=fontthreesix,spread=.1}]

\definefont[DEKFontD][Serif*fontthreesix]
\stoptyping

The \type {spread} (multiplied by the font unit, which is 12 basepoints here)
will add a bit more spacing around the blob:

\startnarrower
\DEKFontD \getbuffer[taocp]
\stopnarrower

Now, keep in mind that we're talking of a real font here. You can cut and paste
these characters. It's just the default uppercase Latin alphabet plus digits.

Before we go and look at some of the code needed to render this, a few more
examples will be given.

\startlinecorrection
    \scale[width=\textwidth]{\DEKFontB 1234567890}    \vskip4pt
    \scale[width=\textwidth]{\DEKFontB ABCDEFGHIJKLM} \vskip4pt
    \scale[width=\textwidth]{\DEKFontB NOPQRSTUVWXYZ}
\stoplinecorrection

In the above example we not only use color, but also a different shape and random
colors (that is: random per \TEX\ job). The feature definition for this is:

\starttyping
\definefontfeature
  [fontthreesix-color]
  [default]
  [metapost={%
    category=fontthreesix,shape=diamond,%
    color=random,pen=fancy,spread=.1%
  }]
\stoptyping

Possible shapes are \type {circle}, \type {diamond} and \type {square} and
instead of a random color one can give a known color name. Using transparency
makes no sense in this font.

A nice usage for this font are initials: % 4 for lm

\startbuffer
\setupinitial[font=Serif*fontthreesix-initial sa 5]
{\DEKFontB \placeinitial \input zapf\par}
\stopbuffer

\typebuffer

The initial feature is defined as:

\starttyping
\definefontfeature
  [fontthreesix-initial]
  [metapost={category=fontthreesix,color=random,shape=circle}]
\stoptyping

We use this in quoting Hermann Zapf, one that for sure is very applicable in
a case like this:

\startnarrower
\getbuffer
\stopnarrower

Some combinations of sub|-|features are shown in \in {figure} [threesix:dek]. We
blow up the diamond with fancy pen example in \in {figure} [threesix:tex]. Alas,
the \TEX\ logo doesn't look that good in such a font. Using it for acronyms is
not a good idea anyway, but maybe you can figure out \in {figure}
[threesix:taocp].

% todo penx peny penr

\definefontfeature
  [fontthreesix-circle]
  [metapost={category=fontthreesix,shape=circle,color=random}]
\definefontfeature
  [fontthreesix-square]
  [metapost={category=fontthreesix,shape=square,color=random}]
\definefontfeature
  [fontthreesix-diamond]
  [metapost={category=fontthreesix,shape=diamond,color=random}]
\definefontfeature
  [fontthreesix-circle-pen]
  [metapost={category=fontthreesix,shape=circle,color=random,pen=fancy}]
\definefontfeature
  [fontthreesix-square-pen]
  [metapost={category=fontthreesix,shape=square,color=random,pen=fancy}]
\definefontfeature
  [fontthreesix-diamond-pen]
  [metapost={category=fontthreesix,shape=diamond,color=random,pen=fancy}]
\definefontfeature
  [fontthreesix-circle-random]
  [metapost={category=fontthreesix,random=yes,shape=circle,color=random}]
\definefontfeature
  [fontthreesix-square-random]
  [metapost={category=fontthreesix,random=yes,shape=square,color=random}]
\definefontfeature
  [fontthreesix-diamond-random]
  [metapost={category=fontthreesix,random=yes,shape=diamond,color=random}]

\definefontfeature
  [fontthreesix-circle-random-spread]
  [metapost={category=fontthreesix,random=yes,shape=circle,color=random,spread=.1}]

\startplacefigure[reference=threesix:dek]
    \startcombination[3*3]
        {\scale[width=.3\textwidth]{\definedfont        [Serif*fontthreesix-circle]D\kern1pt E\kern 1ptK}} {\type{shape=circle}}
        {\scale[width=.3\textwidth]{\definedfont        [Serif*fontthreesix-square]D\kern1pt E\kern 1ptK}} {\type{shape=square}}
        {\scale[width=.3\textwidth]{\definedfont       [Serif*fontthreesix-diamond]D\kern1pt E\kern 1ptK}} {\type{shape=diamond}}
        {\scale[width=.3\textwidth]{\definedfont    [Serif*fontthreesix-circle-pen]D\kern1pt E\kern 1ptK}} {\type{shape=circle,pen=fancy}}
        {\scale[width=.3\textwidth]{\definedfont    [Serif*fontthreesix-square-pen]D\kern1pt E\kern 1ptK}} {\type{shape=square,pen=fancy}}
        {\scale[width=.3\textwidth]{\definedfont   [Serif*fontthreesix-diamond-pen]D\kern1pt E\kern 1ptK}} {\type{shape=diamond,pen=fancy}}
        {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesix-circle-random]D\kern1pt E\kern 1ptK}} {\type{shape=circle,random=yes}}
        {\scale[width=.3\textwidth]{\definedfont [Serif*fontthreesix-square-random]D\kern1pt E\kern 1ptK}} {\type{shape=square,random=yes}}
        {\scale[width=.3\textwidth]{\definedfont[Serif*fontthreesix-diamond-random]D\kern1pt E\kern 1ptK}} {\type{shape=diamond,random=yes}}
    \stopcombination
\stopplacefigure

\startplacefigure[reference=threesix:tex]
\scale[width=\textwidth]{\definedfont[Serif*fontthreesix-diamond-pen]T\lower.5ex\hbox spread .1em{\hss E\hss}X}
\stopplacefigure

\startplacefigure[reference=threesix:taocp]
\scale[width=\textwidth]{\definedfont[Serif*fontthreesix-circle-random-spread]TAOCP}
\stopplacefigure

You can quit reading now or expose yourself to how this is coded. We use a
combination of \LUA\ and \METAPOST, but different solutions are possible. The
shapes are entered (or course) with zeros and ones.

\starttyping
\startluacode
local font36 = {
    ["0"] = "00111100 01111110 11000011 11000011 11000011 ...",
    ["1"] = "00011100 11111100 11101100 00001100 00001100 ...",
    .....
    ["D"] = "11111100 11100010 01100011 01100011 01100011 ...",
    ["E"] = "1111111 1110001 0110101 0111100 0110100 0110001 ...",
    .....
    ["K"] = "11101110 11100100 01101000 01110000 01111000 ...",
    .....
}
\stopluacode
\stoptyping

We also use \LUA\ to register this font. The actual code looks slightly different
because it uses some helpers from the \CONTEXT\ \LUA\ libraries. We remap the
bits pattern onto \METAPOST\ macro calls.

\starttyping
\startluacode
local replace = {
    ["0"] = "N;",
    ["1"] = "Y;",
    [" "] = "L;",
}

function MP.registerthreesix(name)
    fonts.dropins.registerglyphs {
        name     = name,
        units    = 12,
        usecolor = true,
    }
    for u, v in table.sortedhash(font36) do
        local ny     = 8
        local nx     = (#v - ny + 1) // ny
        local height = ny * 1.1 - 0.1
        local width  = nx * 1.1 - 0.1
        local code   = string.gsub(v,".",replace)
        fonts.dropins.registerglyph {
            category = name,
            unicode  = utf.byte(u),
            width    = width,
            height   = height,
            code     = string.format("ThreeSix(%s);",code),
        }
    end
end

MP.registerthreesix("fontthreesix")
\stopluacode
\stoptyping

So, after this the font \type {fontthreesix} is known to the system but we still
need to provide \METAPOST\ code to generate it. The glyphs themselves are now
just sequences of \type {N}, \type {Y} and \type {L} with some wrapper code
around it. The definitions are put in the \type {MP} namespace simply because a
first version initialized in \METAPOST, and there could create variants, but in
the end I settled on the parameter interface at the \TEX\ end.

The next definition looks a bit complex but normally such a macro is
stepwise constructed. Notice how we can query the sub features. In order to make
that possible the regular \METAFUN\ parameter handling code is used. We just push
the sub|-|features into to \type {mpsfont} namespace.

\starttyping
\startMPcalculation{simplefun}

def InitializeThreeSix =
    save Y, N, L, S ; save dx, dy, nx, ny ; save currentpen ;
    save shape, fillcolor, mypen, random, spread, hoffset ;
    string shape, fillcolor, mypen ; boolean random ;
    pen currentpen ;
    dx :=   11/10 ;
    dy := - 11/10 ;
    nx := - dx ;
    ny :=   0 ;
    shape      := getparameterdefault "mpsfont" "shape" "circle" ;
    random     := hasoption           "mpsfont" "random" "true" ;
    fillcolor  := getparameterdefault "mpsfont" "color" "" ;
    mypen      := getparameterdefault "mpsfont" "pen" "" ;
    spread     := getparameterdefault "mpsfont" "spread" 0 ;
    hoffset    := 12 * spread / 2 ;
    currentpen := pencircle
        if mypen = "fancy" :
            xscaled 1/20 yscaled 2/20 rotated 45
        else :
            scaled 1/20
        fi ;
    if shape == "square" :
        def S =
            unitsquare if random : randomized 1/10 fi
            shifted (nx,ny)
        enddef ;
    elseif shape = "diamond" :
        def S =
            unitdiamond if random : randomized 1/10 fi
            shifted (nx,ny)
        enddef ;
    else :
        def S =
            unitcircle if random : randomizedcontrols 1/20 fi
            shifted (nx,ny)
        enddef ;
    fi ;
    def N =
        nx := nx + dx ;
        draw S ;
    enddef ;
    if fillcolor = "random" :
        def Y =
            nx := nx + dx ;
            fillup S withcolor white randomized (2/3,2/3,2/3) ;
        enddef ;
    elseif fillcolor = "" :
        def Y =
            nx := nx + dx ;
            fillup S ;
        enddef ;
    else :
        def Y =
            nx := nx + dx ;
            fillup S withcolor fillcolor ;
        enddef ;
    fi ;
    def L =
        nx := - dx ;
        ny := ny + dy ;
    enddef ;
enddef ;

vardef ThreeSix (text code) =
    InitializeThreeSix ; % todo: once per instance run
    draw image (code) shifted (hoffset,-ny) ;
enddef ;

\stopMPcalculation
\stoptyping

This code is not that efficient in the sense that there's quite some
\METAPOST|-|\LUA|-|\METAPOST\ traffic going on, for instance each parameter check
involves this, but in practice performance is quite okay, certainly for such a
small font. There will be an initializer option some day soon. The \type
{simplefun} is a reference to an \MPLIB\ instance that does load \METAFUN\ but
only the modules that make no sense for this kind of usage. It also enforces
double mode. The calculations wrapper just executes the code and does not place
some (otherwise empty) graphic.

% After playing with the font I see the beauty of the descriptions in the
% pre|-|fascicle 9b but I still feel pretty stupid. Lucky for me there are
% exercises like 999, tagged as \quote {for dummies}, so I'm not alone.

Those who have seen (and|/|or read) \quotation {Concrete Mathematics} will have
noticed the use of inline images, like dice. Dice are also used in \quotation
{pre-fascicle 5a} (I need a few more lives to grasp that, so I stick to the
images for now!). So, to compensate the somewhat complex code above, I will show
how to accomplish that. This time we do all in \METAPOST:

\startMPcalculation{simplefun}

def DiceFrame =
    pickup pencircle scaled 1/2 ;
    draw unitsquare scaled 8 ;
    pickup pencircle scaled 3/2 ;
enddef ;

vardef DiceOne =
    DiceFrame ;
    draw (4,4) ;
enddef ;
vardef DiceTwoA =
    DiceFrame ;
    draw (2,6) ; draw (6,2) ;
enddef ;
vardef DiceTwoB =
    DiceFrame ;
    draw (6,6) ; draw (2,2) ;
enddef ;
vardef DiceTwo =
    if hasoption "mpsfont" "option" "reverse" :
        DiceTwoB
    else :
        DiceTwoA
    fi ;
enddef ;
vardef DiceThreeA =
    DiceFrame ;
    draw (2,6) ; draw (4,4) ; draw (6,2) ;
enddef ;
vardef DiceThreeB =
    DiceFrame ;
    draw (6,6) ; draw (4,4) ; draw (2,2) ;
enddef ;
vardef DiceThree =
    if hasoption "mpsfont" "option" "reverse" :
        DiceThreeB
    else :
        DiceThreeA
    fi ;
enddef ;
vardef DiceFour =
    DiceFrame ;
    draw (2,6) ; draw (6,6) ; draw (2,2) ; draw (6,2) ;
enddef ;
vardef DiceFive =
    DiceFrame ;
    draw (2,6) ; draw (6,6) ; draw (4,4) ; draw (2,2) ; draw (6,2) ;
enddef ;
vardef DiceSix =
    DiceFrame ;
    draw (2,6) ; draw (6,6) ; draw (2,4) ; draw (6,4) ; draw (2,2) ; draw (6,2) ;
enddef ;

vardef DiceBad =
    pickup pencircle scaled 1/2 ;
    draw unitsquare scaled 8 ;
    draw (1,7) -- (7,1) ; draw (1,1) -- (7,7) ;
enddef ;

lmt_registerglyphs [
    name     = "dice",
    units    = 12,
    width    = 8,
    height   = 8,
    depth    = 0,
    usecolor = true,
] ;

lmt_registerglyph [ category = "dice", unicode = "0x2680", code = "DiceOne;" ] ;
lmt_registerglyph [ category = "dice", unicode = "0x2681", code = "DiceTwo;" ] ;
lmt_registerglyph [ category = "dice", unicode = "0x2682", code = "DiceThree;" ] ;
lmt_registerglyph [ category = "dice", unicode = "0x2683", code = "DiceFour;" ] ;
lmt_registerglyph [ category = "dice", unicode = "0x2684", code = "DiceFive;" ] ;
lmt_registerglyph [ category = "dice", unicode = "0x2685", code = "DiceSix;" ] ;

lmt_registerglyph [ category = "dice", private = "invaliddice", code = "DiceBad;" ] ;

\stopMPcalculation

This is not that hard to follow. We define some shapes first. These could have
been assigned to the \type {code} parameter directly but this is nicer. Next we
register the font itself and after that we set glyphs. We also set the official
\UNICODE\ slots. So, copying a dice can either result in a digit or in a
\UNICODE\ slot for a dice. In the example below we switch to a color which
demonstrates that our dice can be colored at the \TEX\ end. It's either that or
coloring at the \METAPOST\ end as both demand a different kind of \TYPETHREE\
embedding trickery.

We actually predefine three features. The digits one will map regular digit in
the input to dice. We accomplish that via a font feature:

\startbuffer
\startluacode
fonts.handlers.otf.addfeature("dice:digits", {
    type      = "substitution",
    order     = { "dice:digits" },
    nocheck   = true,
    data      = {
        [0x30] = "invaliddice",
        [0x31] = 0x2680,
        [0x32] = 0x2681,
        [0x33] = 0x2682,
        [0x34] = 0x2683,
        [0x35] = 0x2684,
        [0x36] = 0x2685,
        [0x37] = "invaliddice",
        [0x38] = "invaliddice",
        [0x39] = "invaliddice",
    },
} )
\stopluacode
\stopbuffer

\typebuffer \getbuffer

This kind of trickery is part of the font machinery used in \CONTEXT\ and permits
runtime adaption of fonts, so we just use the same mechanism. The \type {nocheck}
is needed to avoid this feature not kicking in due to lack of (at the time of
checking) yet undefined dice.

\startbuffer
\definefontfeature
  [dice:normal]
  [default]
  [metapost={category=dice}]
\definefontfeature
  [dice:reverse]
  [default]
  [metapost={category=dice,option=reverse}]
\definefontfeature
  [dice:digits]
  [dice:digits=yes]

\definefont[DiceN] [Serif*dice:normal]
\definefont[DiceD] [Serif*dice:normal,dice:digits]
\definefont[DiceR] [Serif*dice:reverse,dice:digits]

{\DiceD Does 1 it 4 work? And {\darkgreen 3} too?} {\DiceR And how about
{\darkred 3} then? But 8 should sort of fail!}
\stopbuffer

\typebuffer \getbuffer

The six digits and \UNICODE\ characters come out the same:

\startbuffer
\red  \DiceD \dostepwiserecurse   {`1}   {`6}{1}{\char#1\quad}%
\blue \DiceN \dostepwiserecurse{"2680}{"2685}{1}{\char#1\quad}%
\stopbuffer

\typebuffer

\startlinecorrection
    \scale[width=\textwidth]{\getbuffer\unskip}
\stoplinecorrection

It is tempting to implement for instance~7 as two dice (a one to multi mapping in
\OPENTYPE\ speak) but then one has to decide what combination is taken. One can
also implement ligatures so that for instance 12 results in two six dice. But I
think that's over the top and only showing \TEX\ muscles. It is anyway not that
hard to do as we have an interface for that already.

So why not do the dominos as well? Because there are so many dominos we predefine
the shapes and then register the lot in a loop. We have horizontal and vertical
variants. Being lazy I just made two helpers while one could have done but with
some rotation and shifting of the horizontal one. The loop could be a macro but
we don't save much code that way.

\startbuffer
\startMPcalculation{simplefun}

picture Dominos[] ;

Dominos[0] := image() ;
Dominos[1] := image(draw(4,4);) ;
Dominos[2] := image(draw(2,6);draw(6,2););
Dominos[3] := image(draw(2,6);draw(4,4);draw(6,2););
Dominos[4] := image(draw(2,6);draw(6,6);draw(2,2);draw(6,2););
Dominos[5] := image(draw(2,6);draw(6,6);draw(4,4);draw(2,2);draw(6,2););
Dominos[6] := image(draw(2,6);draw(4,6);draw(6,6);draw(2,2);draw(4,2);draw(6,2););

lmt_registerglyphs [
    name     = "dominos",
    units    = 12,
    width    = 16,
    height   = 8,
    depth    = 0,
    usecolor = true,
] ;

def DrawDominoH(expr a, b) =
    draw image (
        pickup pencircle scaled 1/2 ;
        if (getparameterdefault "mpsfont" "color" "") = "black" :
            fillup unitsquare xyscaled (16,8) ;
            draw (8,.5) -- (8,7.5) withcolor white ;
            pickup pencircle scaled 3/2 ;
            draw Dominos[a]
                withpen currentpen
                withcolor white ;
            draw Dominos[b] shifted (8,0)
                withpen currentpen
                withcolor white ;
        else :
            draw unitsquare xyscaled (16,8) ;
            draw (8,0) -- (8,8) ;
            pickup pencircle scaled 3/2 ;
            draw Dominos[a]
                withpen currentpen ;
            draw Dominos[b] shifted (8,0)
                withpen currentpen ;
        fi ;
    ) ;
enddef ;

def DrawDominoV(expr a, b) = % is H rotated and shifted
    draw image (
        pickup pencircle scaled 1/2 ;
        if (getparameterdefault "mpsfont" "color" "") = "black" :
            fillup unitsquare xyscaled (8,16) ;
            draw (.5,8) -- (7.5,8) withcolor white ;
            pickup pencircle scaled 3/2 ;
            draw Dominos[a] rotatedaround(center Dominos[a],90)
                withpen currentpen
                withcolor white  ;
            draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
                withpen currentpen
                withcolor white  ;
        else :
            draw unitsquare xyscaled (8,16) ;
            draw (0,8) -- (8,8) ;
            pickup pencircle scaled 3/2 ;
            draw Dominos[a] rotatedaround(center Dominos[a],90)
                withpen currentpen ;
            draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
                withpen currentpen ;
        fi ;
    ) ;
enddef ;

begingroup
    save unicode ; numeric unicode ; unicode := 127025 ; % 1F031

    for i=0 upto 6 :
        for j=0 upto 6 :
            lmt_registerglyph [
                category = "dominos",
                unicode  = unicode,
                code     = "DrawDominoH(" & decimal i & "," & decimal j & ");",
                width    = 16,
                height   = 8,
            ] ;
            unicode := unicode + 1 ;
        endfor ;
    endfor ;

    save unicode ; numeric unicode ; unicode := 127075 ;

    for i=0 upto 6 :
        for j=0 upto 6 :
            lmt_registerglyph [
                category = "dominos",
                unicode  = unicode,
                code     = "DrawDominoV(" & decimal i & "," & decimal j & ");",
                width    = 8,
                height   = 16,
            ] ;
            unicode := unicode + 1 ;
        endfor ;
    endfor ;
endgroup ;

\stopMPcalculation
\stopbuffer

\typebuffer \getbuffer

Again we predefine a couple of features:

\startbuffer
\definefontfeature
  [dominos:white]
  [default]
  [metapost={category=dominos}]

\definefontfeature
  [dominos:black]
  [default]
  [metapost={category=dominos,color=black}]

\definefontfeature
  [dominos:digits]
  [dominos:digits=yes]
\stopbuffer

\typebuffer \getbuffer

This last feature is yet to be defined. We could deal with the invalid dominos
with some substitution trickery but let's keep it simple.

\startbuffer
\startluacode
local ligatures = { }
local unicode   = 127025

for i=0x30,0x36 do
    for j=0x30,0x36 do
        ligatures[unicode] = { i, j }
        unicode = unicode + 1 ;
    end
end

fonts.handlers.otf.addfeature("dominos:digits", {
    type      = "ligature",
    order     = { "dominos:digits" },
    nocheck   = true,
    data      = ligatures,
} )
\stopluacode
\stopbuffer

\typebuffer \getbuffer

That leaves showing an example. We define a few fonts and again we just extend
the Serif:

\startbuffer
\definefont[DominoW][Serif*dominos:white]
\definefont[DominoB][Serif*dominos:black]
\definefont[DominoD][Serif*dominos:white,dominos:digits]
\stopbuffer

\typebuffer \getbuffer

The example is:

\startbuffer
\DominoW
    \char"1F043\quad 🀱\quad
    \char"1F052\quad 🀲\quad
    \char"1F038\quad 🀳\quad
    \darkgreen\char"1F049\quad \char"1F07B\quad
\DominoB
    \char"1F087\quad
    \char"1F088\quad
    \char"1F089\quad
\DominoD
    \darkred 12\quad56\quad64
\stopbuffer

\typebuffer

Watch the ligatures in action:

\startlinecorrection
    \scale[width=\textwidth]{\getbuffer\unskip}
\stoplinecorrection

To what extent the usage of symbols like dice and dominos as characters in the
mentioned book are responsible for them being in \UNICODE, I don't know. Now with
all these emoji showing up one can wonder about graphics in such a standard
anyway. But for sure, even after more than three decades, Don still makes nice
fonts.

A treasure of tiny graphics can be found in \quotation {pre-fascicle 5c} and many
are in color! In fact, it has dominos too. It must have been a lot of fun writing
this! I'm thinking of turning the pentominoes into a font where a \type {GPOS}
feature can deal with the inter|-|pentomino kerning (which mighty work out okay
for example~36. The windmill dominos also make a nice example for a font where
ligatures will boil down to the base form and the (one or more) blades are laid
over. It's definitely an inspiring read.

\stopchapter

\stoptext