Osiem na osiem, ani jednego więcej
Zestaw znaków Commodore 64 siedzi w ROM-ie i ma dokładnie 2048 bajtów: 256 znaków po 8 bajtów, każdy bajt to jeden wiersz matrycy o szerokości ośmiu pikseli. Rejestr $D018 pozwala wskazać VIC-II inny obszar pamięci, więc własny krój to jedna z pierwszych rzeczy, których uczy się każdy, kto pisze na tę maszynę cokolwiek poza listingiem z gazety.
Czego w tym zestawie nie ma, tego nie ma na zawsze: PETSCII nie zna polskich liter. Ani ą, ani ę, ani ł. Na maszynie z 1982 roku, sprzedawanej w Kalifornii, nikogo to nie dziwiło. Dziwi dziś, kiedy ten sam krój — w wiernej rekonstrukcji jako font TrueType — wraca na ekran współczesnego komputera i okazuje się, że nadal nie da się w nim napisać „żółw".
Ten tekst jest o tym, jak dorysować brakujące dziewięć liter (plus dziewięć wielkich) tak, żeby nikt nie poznał, że nie było ich w oryginale. I o tym, czego nauczyła mnie po drodze litera Ż.
Pikselowy font w przebraniu krzywych
Najwierniejszą dziś rekonstrukcją charsetu C64 jest C64 Pro Mono — font TrueType, w którym każdy znak to nie krzywe Béziera, tylko zwykłe prostokąty ułożone na siatce. To kluczowa właściwość, bo pozwala zrobić rzecz, która w normalnym kroju byłaby wandalizmem.
Font ma 2048 jednostek na firet (em). Osiem pikseli na 2048 jednostek daje 256 jednostek na piksel — okrągłą liczbę, nie żaden ułamek. Znak da się więc zrasteryzować z powrotem do bitmapy 8×8 bezstratnie: wystarczy sprawdzić, czy środek każdego piksela leży wewnątrz konturu.
Wielka litera „O" po takiej konwersji wygląda dokładnie tak, jak wyglądała w ROM-ie:
........ ..####.. .##..##. .##..##. .##..##. .##..##. .##..##. ..####.. ........
I tu przychodzi obserwacja, która rozwiązała cały problem: pierwszy wiersz jest pusty. Wielkie litery zajmują w tym kroju wiersze od pierwszego do siódmego, małe od trzeciego do siódmego. Nad każdą wielką literą zostaje jeden wolny wiersz, a pod linią bazową — drugi.
Dokładnie tyle, ile trzeba na kreskę nad Ó i na ogonek pod Ą. Bez skracania liter, bez rozpychania wierszy.
Dziewiętnaście znaków, których nie było
Reszta jest już mechaniką: bierzemy literę bazową, dokładamy akcent jako piksele, składamy znak z powrotem z prostokątów. Cztery przykłady gotowego wyniku:
Ó Ż Ł Ą ....##.. ...#.... ........ ........ ..####.. .######. .##..... ...##... .##..##. .....##. .##..... ..####.. .##..##. ....##.. .##..... .##..##. .##..##. ...##... ####.... .######. .##..##. ..##.... .##..... .##..##. .##..##. .##..... .##..... .##..##. ..####.. .######. .######. .##..##. ........ ........ ........ ....##..
Ł nie jest akcentem tylko poprzeczką na literze, więc dostaje własną regułę. Ogonki schodzą do wiersza pod linią bazową — tego samego, w którym normalnie mieszkają descendery „g" i „y".
Efekt liczbowo: yMax gotowego fontu wynosi 2048, czyli równo jeden firet. Cały znak — z akcentem i ogonkiem — mieści się w komórce. To nie jest kosmetyka. Gdyby akcent wystawał choćby o piksel, terminal albo ucinałby mu górę, albo trzeba by rozsuwać wiersze, a wtedy ekran przestaje wyglądać jak ekran C64 i zaczyna wyglądać jak edytor tekstu.
Ź kontra Ż, czyli różnica, której nie widać
Pierwsza wersja miała wadę, którą zobaczyłem dopiero na renderze — nie w kodzie, nie w liczbach, dopiero na obrazku.
Ź i Ż różniły się przesunięciem akcentu o jeden piksel w bok. Kreska stała w czwartej kolumnie, kropka w trzeciej. Na wydruku bitmapy różnica jest oczywista, bo widać siatkę. Na ekranie, przy dwunastu punktach, nie ma jej wcale.
Poprawka polegała na zmianie grubości, nie położenia: kreska ma dwa piksele i biegnie w prawo, kropka ma jeden i stoi na środku. Małe litery mają zapas dwóch wolnych wierszy, więc dostały porządny ukośny akcent, na jaki wielkie nie mają miejsca.
Wniosek jest szerszy niż ten jeden font i wart zapamiętania przy każdej robocie w małej rozdzielczości — przy ośmiu pikselach różnicę trzeba projektować tak, żeby ją było widać, a nie tak, żeby dała się policzyć. Sprite'y wrogów w grach rządzą się dokładnie tym samym prawem.
Przy okazji doszły znaki, których oryginał nie ma, a polszczyzna ich potrzebuje: cudzysłów otwierający „, przecinek górny ‚, wielokropek …, półpauza – i myślnik —. Cudzysłowy powstały z przesunięcia istniejących w dół o cztery wiersze; w tym kroju rysuje się je jako dwie grube kreski, więc pasują bez retuszu.
Dlaczego nie dostaniecie gotowego pliku
I tu część, która wymagała więcej namysłu niż kod.
Licencja C64 Pro Mono zabrania dwóch rzeczy naraz: rozpowszechniania pliku i jakiejkolwiek jego modyfikacji. Każde dozwolone użycie ma w niej dopisek „without any modification". Font z dorysowanymi ogonkami jest modyfikacją, więc wypada poza wszystko, na co autor kiedykolwiek się zgodził.
Dlatego w repozytorium nie ma pliku fontu i nigdy nie będzie. Instalator pobiera oryginał prosto ze strony autora, a polskie znaki dorysowuje już na komputerze użytkownika, do jego własnego użytku. Rozdawany jest generator, nie font.
Brzmi drobiazgowo. Ale to jest różnica między „szanujemy pracę autora" a „bierzemy cudze i zmieniamy nazwę" — a w tej branży żyjemy z tego, że ktoś kiedyś zrobił kawał świetnej roboty i udostępnił ją za darmo na jasnych warunkach.
Co z tym zrobić
Wynikiem jest terminal, który wygląda jak ekran C64 i mówi po polsku — paleta VIC-II, migający kursor-blok, ekran powitalny BASIC V2 i zachęta w postaci LOAD"...",8,1. Kod, instalator i dokumentacja leżą tutaj:
👉 github.com/arekbr/c64-terminal-pl
Instalator sam rozpoznaje dystrybucję, robi kopię zapasową plików, które zmienia, i ma tryb --dry-run, jeśli ktoś woli najpierw zobaczyć, co się stanie. Powstał i był testowany na Debianie; konfiguracje dla pozostałych terminali są napisane według ich dokumentacji, ale nieprzeklikane — i tak jest to napisane wprost w opisie projektu.
Sam pomysł nie jest nowy: temat polskich czcionek wraca na scenowych forach od lat — choćby w tym wątku na c64scene.pl. Nowe jest to, że tym razem znaki nie lądują w emulatorze, tylko w oknie, w którym pracuje się codziennie.
Krótszą wersję tej historii — bez rozbierania fontu na czynniki pierwsze — opublikowaliśmy też na stronie SMOK-a.
A jeśli macie ochotę na kolejny krój: Amstrad CPC, ZX Spectrum i Atari czekają w kolejce. Ta sama metoda, inna siatka.