diff options
author | B. Watson <urchlay@slackware.uk> | 2024-07-24 01:16:59 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2024-07-24 01:16:59 -0400 |
commit | 7027ad989c1bcdbd2a9eab8c7d419eda590a0204 (patch) | |
tree | 84d83a41476d1a4cfb3763b068cd6d448d5dea96 /fonts/mkpsf.pl | |
parent | 6deb0d43e2181cffd6faa23369882dac803d5e16 (diff) | |
download | bw-atari8-tools-7027ad989c1bcdbd2a9eab8c7d419eda590a0204.tar.gz |
fonts/* and fauxtari.{rst,7} added. still WIP.
Diffstat (limited to 'fonts/mkpsf.pl')
-rw-r--r-- | fonts/mkpsf.pl | 639 |
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 ) + 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--- \ + -------- \ + -------- \ + -------- \ + -------- |