aboutsummaryrefslogtreecommitdiff
path: root/fonts/mkpsf.pl
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-07-24 01:16:59 -0400
committerB. Watson <urchlay@slackware.uk>2024-07-24 01:16:59 -0400
commit7027ad989c1bcdbd2a9eab8c7d419eda590a0204 (patch)
tree84d83a41476d1a4cfb3763b068cd6d448d5dea96 /fonts/mkpsf.pl
parent6deb0d43e2181cffd6faa23369882dac803d5e16 (diff)
downloadbw-atari8-tools-7027ad989c1bcdbd2a9eab8c7d419eda590a0204.tar.gz
fonts/* and fauxtari.{rst,7} added. still WIP.
Diffstat (limited to 'fonts/mkpsf.pl')
-rw-r--r--fonts/mkpsf.pl639
1 files changed, 639 insertions, 0 deletions
diff --git a/fonts/mkpsf.pl b/fonts/mkpsf.pl
new file mode 100644
index 0000000..1ff5816
--- /dev/null
+++ b/fonts/mkpsf.pl
@@ -0,0 +1,639 @@
+#!/usr/bin/perl -w
+
+# Read raw font data from atari rom images, plus a few hand-drawn
+# "text bitmaps" from __DATA__.
+
+# Write 3 bitmap font "txt" files in the format txt2psf expects, then
+# runs txt2psf on them. Results in 3 fonts:
+
+# fauxtari-8.psf - 8x8 native size
+# fauxtari-16.psf - 16x16 scaled up
+# fauxtari-24.psf - 24x24 scaled up
+
+# The fiddly bits of this are getting the Unicode mappings correct.
+
+# ROM dumps are mapped to Atari address space at $C000, the regular
+# charset starts at $E000, so it's at offset $2000 (8192) in the
+# image. The XL international set is at $CC00, or offset $0C00 (3072).
+# In the Arabic ROM, the Arabic font takes the place of the standard
+# charset. All the charsets are 1K in size.
+
+# Arabic ROM, plus some info about it and a mention of the Hebrew ROM:
+# https://www.savetz.com/vintagecomputers/arabic65xe/
+
+# TODO;
+# BDF fonts too: psf2bdf --iso10646 --fontname <blah> ...
+# Arabic.
+
+use bytes;
+
+$fontname = "fauxtari";
+
+sub byte2line {
+ my $t = shift;
+ $t = sprintf("%08b", $t);
+ $t =~ y/0/-/;
+ $t =~ y/1/#/;
+ return $t;
+}
+
+sub scale_line {
+ my $line = shift;
+ my $scale = shift;
+ my $one = '#' x $scale;
+ my $zero = '-' x $scale;
+
+ $line =~ s/#/$one/g;
+ $line =~ s/-/$zero/g;
+ return ($line x $scale);
+}
+
+sub chr2output {
+ my $codepoint = shift;
+ my $bytes = shift;
+ my $scale = shift || 1;
+ my $unicode = "";
+
+ if(!ref $codepoint) {
+ $codepoint = [ $codepoint ];
+ }
+
+ $unicode .= sprintf("[%04x];", $_) for @$codepoint;
+
+ my $result = sprintf("%%\nUnicode: %s\nBitmap: \\\n", $unicode);
+ for(0..7) {
+ my $byte = $bytes->[$_];
+ my $line = byte2line($byte);
+ $result .= scale_line($line, $scale);
+ $result .= " \\" unless $_ == 7;
+ $result .= "\n";
+ }
+ return $result;
+}
+
+sub internal2byte {
+ my $t = shift;
+ $t =~ y/-/0/;
+ $t =~ y/#/1/;
+ return pack("B*", $t);
+}
+
+sub psf2txt_header {
+ my $charcount = shift;
+ my $scale = shift;
+ my $w = 8 * $scale;
+ my $h = 8 * $scale;
+ return <<EOF;
+%PSF2
+Version: 0
+Flags: 1
+Length: $charcount
+Width: $w
+Height: $h
+EOF
+}
+
+sub read_rom {
+ my $data;
+ my $filename = shift;
+ my $offset = shift;
+ my $charcount = shift;
+ my $len = $charcount * 8;
+ open my $fh, '<', $filename;
+ read($fh, $data, 16384);
+ close $fh;
+ return substr($data, $offset, $len);
+}
+
+# position in the map (array index) is the raw glyph number, in
+# the order we read the font data.
+# value is the Unicode codepoint. if there are multiple codepoints
+# for the glyph, make the value an array ref (see 0x1B below, the
+# Atari Escape glyph is both 0x0118 aka LATIN CAPITAL LETTER E WITH OGONEK,
+# and 0x241b aka SYMBOL FOR ESCAPE).
+sub setup_map {
+ our @map = (
+ 0x2665, # 0x00
+ 0x2523, # 0x01
+ 0x2503, # 0x02
+ 0x251b, # 0x03
+ 0x252b, # 0x04
+ 0x2513, # 0x05
+ 0x2571, # 0x06
+ 0x2572, # 0x07
+ 0x25E2, # 0x08
+ 0x2597, # 0x09
+ 0x25E3, # 0x0A
+ 0x259D, # 0x0B
+ 0x2598, # 0x0C
+ 0x2594, # 0x0D
+ 0x2581, # 0x0E
+ 0x2596, # 0x0F
+ 0x2663, # 0x10
+ 0x250F, # 0x11
+ 0x2501, # 0x12
+ 0x254B, # 0x13
+ 0x25CF, # 0x14
+ 0x2584, # 0x15
+ 0x258E, # 0x16
+ 0x2533, # 0x17
+ 0x253B, # 0x18
+ 0x258C, # 0x19
+ 0x2517, # 0x1A
+ [ 0x0118, 0x241b ], # 0x1B
+ 0x2191, # 0x1C
+ 0x2193, # 0x1D
+ 0x2190, # 0x1E
+ 0x2192, # 0x1F
+ [ 0x0020, 0xa0 ], # 0x20 (plus &nbsp;)
+ 0x0021, # 0x21
+ 0x0022, # 0x22
+ 0x0023, # 0x23
+ 0x0024, # 0x24
+ 0x0025, # 0x25
+ 0x0026, # 0x26
+ 0x0027, # 0x27
+ 0x0028, # 0x28
+ 0x0029, # 0x29
+ 0x002A, # 0x2A
+ 0x002B, # 0x2B
+ 0x002C, # 0x2C
+ [ 0x002D, 0x00ad, 0x2013, 0x2014 ] # 0x2D (plus soft hyphen, en, em)
+ 0x002E, # 0x2E
+ 0x002F, # 0x2F
+ 0x0030, # 0x30
+ 0x0031, # 0x31
+ 0x0032, # 0x32
+ 0x0033, # 0x33
+ 0x0034, # 0x34
+ 0x0035, # 0x35
+ 0x0036, # 0x36
+ 0x0037, # 0x37
+ 0x0038, # 0x38
+ 0x0039, # 0x39
+ 0x003A, # 0x3A
+ 0x003B, # 0x3B
+ 0x003C, # 0x3C
+ 0x003D, # 0x3D
+ 0x003E, # 0x3E
+ 0x003F, # 0x3F
+ 0x0040, # 0x40
+ 0x0041, # 0x41
+ 0x0042, # 0x42
+ 0x0043, # 0x43
+ 0x0044, # 0x44
+ 0x0045, # 0x45
+ 0x0046, # 0x46
+ 0x0047, # 0x47
+ 0x0048, # 0x48
+ 0x0049, # 0x49
+ 0x004A, # 0x4A
+ 0x004B, # 0x4B
+ 0x004C, # 0x4C
+ 0x004D, # 0x4D
+ 0x004E, # 0x4E
+ 0x004F, # 0x4F
+ 0x0050, # 0x50
+ 0x0051, # 0x51
+ 0x0052, # 0x52
+ 0x0053, # 0x53
+ 0x0054, # 0x54
+ 0x0055, # 0x55
+ 0x0056, # 0x56
+ 0x0057, # 0x57
+ 0x0058, # 0x58
+ 0x0059, # 0x59
+ 0x005A, # 0x5A
+ 0x005B, # 0x5B
+ 0x005C, # 0x5C
+ 0x005D, # 0x5D
+ 0x005E, # 0x5E
+ 0x005F, # 0x5F
+ 0x25C6, # 0x60
+ 0x0061, # 0x61
+ 0x0062, # 0x62
+ 0x0063, # 0x63
+ 0x0064, # 0x64
+ 0x0065, # 0x65
+ 0x0066, # 0x66
+ 0x0067, # 0x67
+ 0x0068, # 0x68
+ 0x0069, # 0x69
+ 0x006A, # 0x6A
+ 0x006B, # 0x6B
+ 0x006C, # 0x6C
+ 0x006D, # 0x6D
+ 0x006E, # 0x6E
+ 0x006F, # 0x6F
+ 0x0070, # 0x70
+ 0x0071, # 0x71
+ 0x0072, # 0x72
+ 0x0073, # 0x73
+ 0x0074, # 0x74
+ 0x0075, # 0x75
+ 0x0076, # 0x76
+ 0x0077, # 0x77
+ 0x0078, # 0x78
+ 0x0079, # 0x79
+ 0x007A, # 0x7A
+ 0x2660, # 0x7B
+ [ 0x007C, 0x0622, 0xFE81, 0xFE82 ], # 0x7C, pipe + Arabic ﺁ
+ 0x21B0, # 0x7D
+ 0x25C0, # 0x7E
+ 0x25B6, # 0x7F
+
+# Next, 28 "international" characters from the XL ROM $CC00 area
+# á
+ 0x00e1, # 0x80
+# ù
+ 0x00f9, # 0x81
+# Ñ
+ 0x00d1, # 0x82
+# É
+ 0x00c9, # 0x83
+# ç
+ 0x00e7, # 0x84
+# ô (or is it?)
+ 0x00f4, # 0x85
+# ò
+ 0x00f2, # 0x86
+# ì
+ 0x00ec, # 0x87
+# £
+ 0x00a3, # 0x88
+# ï
+ 0x00ef, # 0x89
+# ü
+ 0x00fc, # 0x8a
+# ä
+ 0x00e4, # 0x8b
+# Ö
+ 0x00d6, # 0x8c
+# ú
+ 0x00fa, # 0x8d
+# ó
+ 0x00f3, # 0x8e
+# ö
+ 0x00f6, # 0x8f
+# Ü
+ 0x00dc, # 0x90
+# å
+ 0x00e5, # 0x91
+# û (?)
+ 0x00fb, # 0x92
+# î
+ 0x00ee, # 0x93
+# é
+ 0x00e9, # 0x94
+# è
+ 0x00e8, # 0x95
+# ñ
+ 0x00f1, # 0x96
+# ê
+ 0x00ea, # 0x97
+# ȧ
+ 0x0227, # 0x98
+# à
+ 0x00e0, # 0x99
+# ¡
+ 0x00a1, # 0x9a
+# Ä
+ 0x00c4, # 0x9b
+
+# Hebrew ROM is probably a 3rd-party hack, AFAIK never released by
+# Atari, but I'm told the glyphs look good (by someone who reads Hebrew),
+# so include it here.
+ 0x05d0, # 0x9c
+ 0x05d1, # 0x9d
+ 0x05d2, # 0x9e
+ 0x05d3, # 0x9f
+ 0x05d4, # 0xa0
+ 0x05d5, # 0xa1
+ 0x05d6, # 0xa2
+ 0x05d7, # 0xa3
+ 0x05d8, # 0xa4
+ 0x05d9, # 0xa5
+ 0x05da, # 0xa6
+ 0x05db, # 0xa7
+ 0x05dc, # 0xa8
+ 0x05dd, # 0xa9
+ 0x05de, # 0xaa
+ 0x05df, # 0xab
+ 0x05e0, # 0xac
+ 0x05e1, # 0xad
+ 0x05e2, # 0xae
+ 0x05e3, # 0xaf
+ 0x05e4, # 0xb0
+ 0x05e5, # 0xb1
+ 0x05e6, # 0xb2
+ 0x05e7, # 0xb3
+ 0x05e8, # 0xb4
+ 0x05e9, # 0xb5
+ 0x05ea, # 0xb6
+
+# Polish ROM. Probably a 3rd-party hack, but there are a lot of Polish
+# Atari users out there.
+ 0x0179, # 0xb7
+ 0x0105, # 0xb8
+ 0x017a, # 0xb9
+ 0x0107, # 0xba
+ 0x015a, # 0xbb
+ 0x0119, # 0xbc
+# German sharp S, not Polish at all:
+ 0x00df, # 0xbd
+ 0x0141, # 0xbe
+ 0x0142, # 0xbf
+ 0x0143, # 0xc0
+ 0x0144, # 0xc1
+ 0x00f3, # 0xc2
+ 0x00d3, # 0xc3
+# 0xc3 weird-looking V?
+# next glyph is E with ogonek, we already have it as ESC
+ 0x015b, # 0xc4
+ 0x0106, # 0xc5
+ 0x0104, # 0xc6
+ 0x017b, # 0xc7
+ 0x017c, # 0xc8
+
+# The rest are from the Arabic XE ROM
+ 0x0660, # eastern arabic numeral 0
+ 0x0661, # eastern arabic numeral 1
+ 0x0662, # eastern arabic numeral 2
+ 0x0663, # eastern arabic numeral 3
+ 0x0664, # eastern arabic numeral 4
+ 0x0665, # eastern arabic numeral 5
+ 0x0666, # eastern arabic numeral 6
+ 0x0667, # eastern arabic numeral 7
+ 0x0668, # eastern arabic numeral 8
+ 0x0669, # eastern arabic numeral 9
+
+# TODO: figure out the Arabic letter mappings. Might need someone who
+# actually reads Arabic to make sense of them... what I've got is just
+# a guess.
+ [ 0x0624, 0xfeb5, 0xfeb6 ], # 0x3c, maybe?
+
+ [ 0x0634, 0xFEB5, 0xFEB6, 0xFEB8 ], # 0x41
+ [ 0x0648, 0xFEED, 0xFEEE ], # 0x42
+ [ 0x0629, 0xFE93, 0xFE94 ], # 0x43
+ [ 0x064A, 0xFEF1, 0xFEF2, 0xFEF4 ], # 0x44
+ [ 0x062B, 0xFE99, 0xFE9A, 0xFE9C ], # 0x45
+ [ 0x0628, 0xFE8F, 0xFE90, 0xFE92 ], # 0x46
+ [ 0x0644, 0xFEDD, 0xFEDE, 0xFEE0 ], # 0x47
+ [ 0x0621, 0xfe80 ], # 0x48
+ [ 0x0647, 0xFEE9, 0xFEEA, 0xFEEC ], # 0x49
+ [ 0x062A, 0xFE95, 0xFE96, 0xFE98 ], # 0x4a
+ [ 0x0646, 0xFEE5, 0xFEE6, 0xFEE8 ], # 0x4b
+ [ 0x0645, 0xFEE1, 0xFEE2, 0xFEE4 ], # 0x4c
+ [ 0x062C, 0xFE9D, 0xFE9E, 0xFEA0 ], # 0x4d
+ # XXX don't know what 0x4e is
+ [ 0x062E, 0xFEA5, 0xFEA6, 0xFEA8 ], # 0x4f
+ [ 0x062D, 0xFEA1, 0xFEA2, 0xFEA4 ], # 0x50
+ [ 0x0636, 0xFEBD, 0xFEBE, 0xFEC0 ], # 0x51
+ [ 0x0642, 0xFED5, 0xFED6, 0xFED8 ], # 0x52
+ [ 0x0633, 0xFEB1, 0xFEB2, 0xFEB4 ], # 0x53
+ [ 0x0641, 0xFED1, 0xFED2, 0xFED4 ], # 0x54
+ [ 0x0639, 0xFEC9, 0xFECA, 0xFECC ], # 0x55
+ [ 0x0643, 0xFED9, 0xFEDA, 0xFEDC ], # 0x56
+ [ 0x0635, 0xFEB9, 0xFEBA, 0xFEBC ], # 0x57
+ # XXX don't know what 0x58 is
+ [ 0x063A, 0xFECD, 0xFECE, 0xFED0 ], # 0x59
+ [ 0x0649, 0xFEEF, 0xFEF0 ], # 0x5a
+ [ 0x0632, 0xFEAF, 0xFEB0 ], # 0x60
+ 0xFEB7, # 0x61
+ # XXX 0x62 isn't really both ﺩ and ﺭ but where's the Atari's ﺭ at?
+ [ 0x062F, 0xFEA9, 0xFEAA, 0x0631, 0xFEAD, 0xFEAE ], # 0x62
+ [ 0x0630, 0xFEAB, 0xFEAC ], # 0x63
+ 0xFEF3, # 0x64
+ 0xFE9B, # 0x65
+ 0xFE91, # 0x66
+ 0xFEDF, # 0x67
+ [ 0x0627, 0xFE8D, 0xFE8E ], # 0x68
+ 0xFEEB, # 0x69
+ 0xFE97, # 0x6a
+ 0xFEE7, # 0x6b
+ 0xFEE3, # 0x6c
+ 0xFE9F, # 0x6d
+ [ 0xfef7, 0xf3f8 ], # 0x6e
+ 0xFEA7, # 0x6f
+ 0xFEA3, # 0x70
+ 0xFEBF, # 0x71
+ 0xFED7, # 0x72
+ 0xFEB3, # 0x73
+ 0xFED3, # 0x74
+ 0xFECB, # 0x75
+ 0xFEDB, # 0x76
+ 0xFEBB, # 0x77
+ [ 0x0637, 0xFEC1, 0xFEC2, 0xFEC4, 0xFEC3 ], # 0x78
+ 0xFECF, # 0x79
+ [ 0x0638, 0xFEC5, 0xFEC6, 0xFEC8, 0xFEC7 ], # 0x7a
+ 0x061F, # 0x7f
+ );
+}
+
+### main()
+setup_map();
+
+@scale1 = ();
+@scale2 = ();
+@scale3 = ();
+
+#$raw = read_rom("atarixl.rom", 0x2000, 128);
+$raw = read_rom("atarixl.rom", 0x2200, 32);
+$raw .= read_rom("atarixl.rom", 0x2000, 32);
+$raw .= read_rom("atarixl.rom", 0x2100, 32);
+$raw .= read_rom("atarixl.rom", 0x2300, 32);
+$raw .= read_rom("atarixl.rom", 0xe00, 26);
+$raw .= read_rom("atarixl.rom", 0xf00, 1);
+$raw .= read_rom("atarixl.rom", 0xfd8, 1);
+$raw .= read_rom("xl_hebrew.rom", 0xe00, 27);
+$raw .= read_rom("xl_polish.rom", 0xe00, 6);
+$raw .= read_rom("xl_polish.rom", 0xe50, 7);
+$raw .= read_rom("xl_polish.rom", 0xe98, 1);
+$raw .= read_rom("xl_polish.rom", 0xeb0, 3);
+$raw .= read_rom("xl_polish.rom", 0xed0, 1);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*15, 10);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x3c, 1);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x41, 13);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x4f, 9);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x59, 2);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x60, 27);
+$raw .= read_rom("xe_arabic.rom", 0x2000+8*0x7f, 1);
+#warn length($raw) / 8;
+##$raw = read_rom("arabicxe.rom", 0x2000, 128);
+#$cnt = 0x9a;
+$cnt = 0;
+while($raw =~ /(.{8})/gc) {
+ my @bytes;
+ my $got = $1;
+ my $chr = $map[$cnt++];
+ die "incomplete map" unless defined $chr;
+ #warn $got;
+ push @bytes, ord(substr($got, $_, 1)) for(0..7);
+ #warn $_ for @bytes;
+ push @scale1, chr2output($chr, \@bytes, 1);
+ push @scale2, chr2output($chr, \@bytes, 2);
+ push @scale3, chr2output($chr, \@bytes, 3);
+}
+
+while(<DATA>) {
+ push @scale1, $_;
+ $cnt++ if /^%/;
+ if(/^\s/) {
+ push @scale2, scale_line($_, 2);
+ push @scale3, scale_line($_, 3);
+ } else {
+ push @scale2, $_;
+ push @scale3, $_;
+ }
+}
+
+warn "$cnt characters\n";
+#warn "(padding to 256 characters)\n" unless $cnt >= 256;
+warn "(padding to 512 characters)\n" unless $cnt >= 512;
+while($cnt < 512) {
+ my $fake = "%\nUnicode: [0000];\nBitmap: ";
+ push @scale1, $fake . (("-" x 8) x 8) . "\n";
+ push @scale2, $fake . (("-" x 16) x 16) . "\n";
+ push @scale3, $fake . (("-" x 24) x 24) . "\n";
+ $cnt++;
+}
+warn "$cnt characters with padding\n";
+
+open $fh, '>', "$fontname-8.txt" or die $!;
+print $fh psf2txt_header($cnt, 1);
+print $fh $_ for(@scale1);
+close $fh;
+system("txt2psf $fontname-8.txt $fontname-8.psf");
+
+open $fh, '>', "$fontname-16.txt" or die $!;
+print $fh psf2txt_header($cnt, 2);
+print $fh $_ for(@scale2);
+close $fh;
+system("txt2psf $fontname-16.txt $fontname-16.psf");
+
+open $fh, '>', "$fontname-24.txt" or die $!;
+print $fh psf2txt_header($cnt, 3);
+print $fh $_ for(@scale3);
+close $fh;
+system("txt2psf $fontname-24.txt $fontname-24.psf");
+
+__DATA__
+%
+// backtick
+Unicode: [0060];
+Bitmap: \
+ -------- \
+ --##---- \
+ --##---- \
+ ---##--- \
+ -------- \
+ -------- \
+ -------- \
+ --------
+%
+// curlies
+Unicode: [007b];
+Bitmap: \
+ ----##-- \
+ ---##--- \
+ ---##--- \
+ --##---- \
+ ---##--- \
+ ---##--- \
+ ----##-- \
+ --------
+%
+Unicode: [007d];
+Bitmap: \
+ --##---- \
+ ---##--- \
+ ---##--- \
+ ----##-- \
+ ---##--- \
+ ---##--- \
+ --##---- \
+ --------
+%
+// tilde
+Unicode: [007e];
+Bitmap: \
+ -------- \
+ -###--## \
+ ##-##-## \
+ ##--###- \
+ -------- \
+ -------- \
+ -------- \
+ --------
+%
+// euro
+Unicode: [20ac];
+Bitmap: \
+ ---####- \
+ --##---- \
+ -#####-- \
+ --##---- \
+ -#####-- \
+ --##---- \
+ ---####- \
+ --------
+%
+// spanish left-quote
+Unicode: [00ab];
+Bitmap: \
+ -------- \
+ -------- \
+ -------- \
+ -##--##- \
+ ##--##-- \
+ -##--##- \
+ -------- \
+ --------
+%
+// spanish right-quote
+Unicode: [00bb];
+Bitmap: \
+ -------- \
+ -------- \
+ -------- \
+ ##--##-- \
+ -##--##- \
+ ##--##-- \
+ -------- \
+ --------
+%
+// spanish inverted question mark
+Unicode: [00bf];
+Bitmap: \
+ -------- \
+ ---##--- \
+ -------- \
+ ---##--- \
+ ----##-- \
+ -##--##- \
+ --####-- \
+ --------
+%
+// copyright
+Unicode: [00a9];
+Bitmap: \
+ -#####-- \
+ #-----#- \
+ #--##-#- \
+ #-#---#- \
+ #--##-#- \
+ #-----#- \
+ -#####-- \
+ --------
+%
+// degrees
+Unicode: [00b0];[00ba];
+Bitmap: \
+ -------- \
+ ---XX--- \
+ --x--x-- \
+ ---xx--- \
+ -------- \
+ -------- \
+ -------- \
+ --------