Implement a default lowercase font for Apple IIe, from John Macdougall's LCA
authorNick Downing <nick@ndcode.org>
Mon, 20 Jun 2022 05:11:42 +0000 (15:11 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 20 Jun 2022 05:11:42 +0000 (15:11 +1000)
.gitignore
emu_65c02/cg_default/John Macdougall LowerCase Adapter (LCA) Alt-1.pdf [new file with mode: 0644]
emu_65c02/cg_default/Makefile
emu_65c02/cg_default/cg_extract.py
emu_65c02/cg_default/cg_verify.py
emu_65c02/emu_65c02.c

index e6c7641..9742e4f 100644 (file)
 /disasm/star_blazer.asm0
 /disasm/star_blazer.dsk
 /emu_65c02/emu_65c02
+/emu_65c02/cg_default/*.inc
 /emu_65c02/cg_default/*.pbm
 /emu_65c02/cg_default/*.png
-/emu_65c02/cg_default/cg_default.inc
+/emu_65c02/cg_default/*.ppm
 /orig/APPLE Computer and Peripheral Card Roms Collection.zip
 /orig/Apple_DOS_v3.3_1980_Apple.do
 /orig/Star_Blazer_1981_Star_Craft.do
diff --git a/emu_65c02/cg_default/John Macdougall LowerCase Adapter (LCA) Alt-1.pdf b/emu_65c02/cg_default/John Macdougall LowerCase Adapter (LCA) Alt-1.pdf
new file mode 100644 (file)
index 0000000..0d6d2dd
Binary files /dev/null and b/emu_65c02/cg_default/John Macdougall LowerCase Adapter (LCA) Alt-1.pdf differ
index 6d33360..9036464 100644 (file)
@@ -1,20 +1,31 @@
+.PHONY: all
+all: \
+cg_signetics.inc \
+signetics1.png \
+cg_katakana.inc \
+katakana1.png \
+cg_lowercase_20.inc \
+lowercase_201.png \
+cg_lowercase_40.inc \
+lowercase_401.png \
+cg_lowercase_60.inc \
+lowercase_601.png
+
+# signetics 2513
 # diagrams have 5 * 8 cell characters at 8.75 * 10.33 cell spacing
 # reduce each cell down to 8 * 6 pixels
 # new diagram will have 40 * 48 pixel characters at 70 * 62 pixel spacing
 
-.PHONY: all
-all: cg_default.inc ascii1.png katakana1.png
+cg_signetics.inc: cg_signetics.png
+       ./cg_compile.py cg_signetics $< >$@
 
-cg_default.inc: cg_ascii.png
-       ./cg_compile.py cg_default $< >$@
+signetics1.png: cg_signetics.png
+       ./cg_verify.py 70,62 8,6 5,8 $< $@
 
-ascii1.png: cg_ascii.png
-       ./cg_verify.py $< $@
+cg_signetics.png: signetics0.png
+       ./cg_extract.py 70,62 8,6 5,8 .333 $< $@
 
-cg_ascii.png: ascii.png
-       ./cg_extract.py $< $@
-
-ascii.png: ascii.pbm
+signetics0.png: signetics.pbm
        convert $< \
 -grayscale Rec709Luminance \
 -distort Perspective \
@@ -22,17 +33,20 @@ ascii.png: ascii.pbm
 -crop 560x496+0+0 \
 $@
 
-ascii.pbm: signetics2513.pdf 
+signetics.pbm: signetics2513.pdf 
        pdfimages -f 7 -l 7 $< a
        mv a-000.pbm $@
 
+cg_katakana.inc: cg_katakana.png
+       ./cg_compile.py cg_katakana $< >$@
+
 katakana1.png: cg_katakana.png
-       ./cg_verify.py $< $@
+       ./cg_verify.py 70,62 8,6 5,8 $< $@
 
-cg_katakana.png: katakana.png
-       ./cg_extract.py $< $@
+cg_katakana.png: katakana0.png
+       ./cg_extract.py 70,62 8,6 5,8 .333 $< $@
 
-katakana.png: katakana.pbm
+katakana0.png: katakana.pbm
        convert $< \
 -grayscale Rec709Luminance \
 -distort Perspective \
@@ -44,5 +58,74 @@ katakana.pbm: signetics2513.pdf
        pdfimages -f 8 -l 8 $< a
        mv a-000.pbm $@
 
+# LCA
+# diagrams have 5 * 8 cell characters at 19 * 13 cell spacing
+# reduce each cell down to 8 * 6 pixels
+# new diagram will have 40 * 48 pixel characters at 152 * 78 pixel spacing
+
+cg_lowercase_20.inc: cg_lowercase_20.png
+       ./cg_compile.py cg_lowercase_20 $< >$@
+
+lowercase_201.png: cg_lowercase_20.png
+       ./cg_verify.py 152,78 8,6 5,8 $< $@
+
+cg_lowercase_20.png: lowercase_200.png
+       ./cg_extract.py 152,78 8,6 5,8 .667 $< $@
+
+lowercase_200.png: lowercase_20.ppm
+       convert $< \
+-grayscale Rec709Luminance \
+-distort Perspective \
+"2025,778 168,0  2028,2879 1080,0  568,413 8,234  569,2864 1072,234" \
+-crop 1216x312+0+0 \
+$@
+
+lowercase_20.ppm: John\ Macdougall\ LowerCase\ Adapter\ (LCA)\ Alt-1.pdf
+       pdfimages -f 13 -l 13 "$<" a
+       mv a-000.ppm $@
+
+cg_lowercase_40.inc: cg_lowercase_40.png
+       ./cg_compile.py cg_lowercase_40 $< >$@
+
+lowercase_401.png: cg_lowercase_40.png
+       ./cg_verify.py 152,78 8,6 5,8 $< $@
+
+cg_lowercase_40.png: lowercase_400.png
+       ./cg_extract.py 152,78 8,6 5,8 .667 $< $@
+
+lowercase_400.png: lowercase_40.ppm
+       convert $< \
+-grayscale Rec709Luminance \
+-distort Perspective \
+"505,2879 8,0  505,429 1072,0  1967,2895 0,234  2227,460 1056,276" \
+-crop 1216x312+0+0 \
+$@
+#458
+
+lowercase_40.ppm: John\ Macdougall\ LowerCase\ Adapter\ (LCA)\ Alt-1.pdf
+       pdfimages -f 12 -l 12 "$<" a
+       mv a-000.ppm $@
+
+cg_lowercase_60.inc: cg_lowercase_60.png
+       ./cg_compile.py cg_lowercase_60 $< >$@
+
+lowercase_601.png: cg_lowercase_60.png
+       ./cg_verify.py 152,78 8,6 5,8 $< $@
+
+cg_lowercase_60.png: lowercase_600.png
+       ./cg_extract.py 152,78 8,6 5,8 .667 $< $@
+
+lowercase_600.png: lowercase_60.ppm
+       convert $< \
+-grayscale Rec709Luminance \
+-distort Perspective \
+"510,2880 8,0  585,428 1072,12  2048,2896 0,246  1972,478 1048,234" \
+-crop 1216x312+0+0 \
+$@
+
+lowercase_60.ppm: John\ Macdougall\ LowerCase\ Adapter\ (LCA)\ Alt-1.pdf
+       pdfimages -f 18 -l 18 "$<" a
+       mv a-000.ppm $@
+
 clean:
-       rm -f *.pbm *.png cg_default.inc
+       rm -f *.inc *.pbm *.png *.ppm
index b08519d..a55e514 100755 (executable)
@@ -7,22 +7,15 @@ import PIL.Image
 EXIT_SUCCESS = 0
 EXIT_FAILURE = 1
 
-PITCH_X = 70
-PITCH_Y = 62
-
-CELL_X = 8
-CELL_Y = 6
-
-CHAR_X = 5
-CHAR_Y = 8
-
-THRESHOLD = .333
-
-if len(sys.argv) < 3:
-  print(f'usage: {sys.argv[0]} in.png out.png')
+if len(sys.argv) < 7:
+  print(f'usage: {sys.argv[0]} pitch_(x,y) cell_(x,y) char_(x,y) threshold in.png out.png')
   sys.exit(EXIT_FAILURE)
-in_png = sys.argv[1]
-out_png = sys.argv[2]
+[pitch_x, pitch_y] = [int(i) for i in sys.argv[1].split(',')]
+[cell_x, cell_y] = [int(i) for i in sys.argv[2].split(',')]
+[char_x, char_y] = [int(i) for i in sys.argv[3].split(',')]
+threshold = float(sys.argv[4])
+in_png = sys.argv[5]
+out_png = sys.argv[6]
 
 image_in_pil = PIL.Image.open(in_png)
 assert image_in_pil.mode == 'L'
@@ -36,31 +29,32 @@ mask = image_in < 12.92 * .0031308
 image_in[mask] *= 1. / 12.92
 image_in[~mask] = ((1. / 1.055) * image_in[~mask] + (.055 / 1.055)) ** 2.4
 
-assert image_in.shape[0] % PITCH_Y == 0
-n_rows = image_in.shape[0] // PITCH_Y
-assert image_in.shape[1] == 8 * PITCH_X
+assert image_in.shape[0] % pitch_y == 0
+n_rows = image_in.shape[0] // pitch_y
+assert image_in.shape[1] % pitch_x == 0
+n_cols = image_in.shape[1] // pitch_x
 
-image_out = numpy.zeros((n_rows * CHAR_Y, 8 * CHAR_X), bool)
+image_out = numpy.zeros((n_rows * char_y, n_cols * char_x), bool)
 
 for i in range(n_rows):
-  y0 = i * PITCH_Y
-  y1 = i * CHAR_Y
-  for j in range(8):
-    x0 = j * PITCH_X
-    x1 = j * CHAR_X
-    shape0 = image_in[y0:y0 + CHAR_Y * CELL_Y, x0:x0 + CHAR_X * CELL_X]
+  y0 = i * pitch_y
+  y1 = i * char_y
+  for j in range(n_cols):
+    x0 = j * pitch_x
+    x1 = j * char_x
+    shape0 = image_in[y0:y0 + char_y * cell_y, x0:x0 + char_x * cell_x]
     shape1 = numpy.mean(
       numpy.stack(
         [
-          shape0[k::CELL_Y, l::CELL_X]
-          for k in range(2, CELL_Y - 1)
-          for l in range(2, CELL_X - 1)
+          shape0[k::cell_y, l::cell_x]
+          for k in range(1, cell_y)
+          for l in range(1, cell_x)
         ],
         2
       ),
       2
-    ) < THRESHOLD
-    image_out[y1:y1 + CHAR_Y, x1:x1 + CHAR_X] = shape1
+    ) < threshold
+    image_out[y1:y1 + char_y, x1:x1 + char_x] = shape1
 
 image_out_pil = PIL.Image.new(
   'P',
index d1f025e..7b90805 100755 (executable)
@@ -7,20 +7,14 @@ import PIL.Image
 EXIT_SUCCESS = 0
 EXIT_FAILURE = 1
 
-PITCH_X = 70
-PITCH_Y = 62
-
-CELL_X = 8
-CELL_Y = 6
-
-CHAR_X = 5
-CHAR_Y = 8
-
-if len(sys.argv) < 3:
-  print(f'usage: {sys.argv[0]} in.png out.png')
+if len(sys.argv) < 6:
+  print(f'usage: {sys.argv[0]} pitch_(x,y) cell_(x,y) char_(x,y) in.png out.png')
   sys.exit(EXIT_FAILURE)
-in_png = sys.argv[1]
-out_png = sys.argv[2]
+[pitch_x, pitch_y] = [int(i) for i in sys.argv[1].split(',')]
+[cell_x, cell_y] = [int(i) for i in sys.argv[2].split(',')]
+[char_x, char_y] = [int(i) for i in sys.argv[3].split(',')]
+in_png = sys.argv[4]
+out_png = sys.argv[5]
 
 image_in_pil = PIL.Image.open(in_png)
 assert image_in_pil.mode == 'P'
@@ -29,30 +23,31 @@ image_in = numpy.frombuffer(
   dtype = numpy.uint8
 ).reshape((image_in_pil.size[1], image_in_pil.size[0])).astype(bool)
 
-assert image_in.shape[0] % CHAR_Y == 0
-n_rows = image_in.shape[0] // CHAR_Y
-assert image_in.shape[1] == 8 * CHAR_X
+assert image_in.shape[0] % char_y == 0
+n_rows = image_in.shape[0] // char_y
+assert image_in.shape[1] % char_x == 0
+n_cols = image_in.shape[1] // char_x
 
-image_out = numpy.ones((n_rows * PITCH_Y, 8 * PITCH_X), numpy.float32)
+image_out = numpy.ones((n_rows * pitch_y, n_cols * pitch_x), numpy.float32)
 
 shape1 = numpy.full(
-  (CHAR_Y * CELL_Y + 1, CHAR_X * CELL_X + 1),
+  (char_y * cell_y + 1, char_x * cell_x + 1),
   .5,
   numpy.float32
 )
 for i in range(n_rows):
-  y0 = i * CHAR_Y
-  y1 = i * PITCH_Y
-  for j in range(8):
-    x0 = j * CHAR_X
-    x1 = j * PITCH_X
-    shape0 = image_in[y0:y0 + CHAR_Y, x0:x0 + CHAR_X]
-    for k in range(1, CELL_Y):
-      for l in range(1, CELL_X):
-        shape1[k:-1:CELL_Y, l:-1:CELL_X] = numpy.logical_not(shape0)
+  y0 = i * char_y
+  y1 = i * pitch_y
+  for j in range(n_cols):
+    x0 = j * char_x
+    x1 = j * pitch_x
+    shape0 = image_in[y0:y0 + char_y, x0:x0 + char_x]
+    for k in range(1, cell_y):
+      for l in range(1, cell_x):
+        shape1[k:-1:cell_y, l:-1:cell_x] = numpy.logical_not(shape0)
     image_out[
-      y1:y1 + CHAR_Y * CELL_Y + 1,
-      x1:x1 + CHAR_X * CELL_X + 1
+      y1:y1 + char_y * cell_y + 1,
+      x1:x1 + char_x * cell_x + 1
     ] = shape1
 
 mask = image_out < .0031308
index b4d746f..e17dd40 100644 (file)
@@ -15,7 +15,7 @@
 #include "stty_sane.h"
 #include "vrEmu6502/src/vrEmu6502.h"
 
-#define APPLE_IIE 0
+#define APPLE_IIE 1
 #define APPLE_WIDTH 560
 #define APPLE_HEIGHT 192
 #define APPLE_TEXT1 0x400
@@ -149,7 +149,13 @@ uint32_t mono_palette[2] = {0xff000000, 0xffffffff};
 
 VrEmu6502 *cpu;
 
-#include "cg_default/cg_default.inc"
+#if APPLE_IIE
+#include "cg_default/cg_lowercase_20.inc"
+#include "cg_default/cg_lowercase_40.inc"
+#include "cg_default/cg_lowercase_60.inc"
+#else
+#include "cg_default/cg_signetics.inc"
+#endif
 
 #define CG_ROM_SIZE 0x800
 uint8_t *cg_rom;
@@ -914,15 +920,13 @@ void termios_atexit(void) {
 int main(int argc, char **argv) {
   int argn = 1;
   char *cg_rom_file = NULL;
+  char *video_rom_file = NULL;
 #if APPLE_IIE
-  char *video_rom_file =
-    "Apple IIe Video Enhanced - 342-0265-A - 2732.bin";
   char *cd_rom_file =
     "Apple IIe CD Enhanced - 342-0304-A - 2764.bin";
   char *ef_rom_file =
     "Apple IIe EF Enhanced - 342-0303-A - 2764.bin";
 #else
-  char *video_rom_file = NULL;
   char *d0_rom_file =
     "Apple II+ - 341-0011 - Applesoft BASIC D000 - 2716.bin";
   char *d8_rom_file =
@@ -1011,9 +1015,23 @@ int main(int argc, char **argv) {
     }
     if (cg_rom_file)
       rom_load(cg_rom_file, cg_rom, CG_ROM_SIZE);
-    else
-      for (int i = 0; i < 4; ++i)
-        memcpy(cg_rom + (i << 9), cg_default, CG_DEFAULT_SIZE);
+    else {
+#if APPLE_IIE
+      memcpy(cg_rom, cg_lowercase_40, CG_LOWERCASE_40_SIZE);
+      memcpy(cg_rom + 0x100, cg_lowercase_20, CG_LOWERCASE_20_SIZE);
+      memcpy(cg_rom + 0x200, cg_lowercase_40, CG_LOWERCASE_40_SIZE);
+      memcpy(cg_rom + 0x300, cg_lowercase_20, CG_LOWERCASE_20_SIZE);
+      memcpy(cg_rom + 0x400, cg_lowercase_40, CG_LOWERCASE_40_SIZE);
+      memcpy(cg_rom + 0x500, cg_lowercase_20, CG_LOWERCASE_20_SIZE);
+      memcpy(cg_rom + 0x600, cg_lowercase_40, CG_LOWERCASE_40_SIZE);
+      memcpy(cg_rom + 0x700, cg_lowercase_60, CG_LOWERCASE_60_SIZE);
+#else
+      memcpy(cg_rom, cg_signetics, CG_SIGNETICS_SIZE);
+      memcpy(cg_rom + 0x200, cg_signetics, CG_SIGNETICS_SIZE);
+      memcpy(cg_rom + 0x400, cg_signetics, CG_SIGNETICS_SIZE);
+      memcpy(cg_rom + 0x600, cg_signetics, CG_SIGNETICS_SIZE);
+#endif
+    }
   }
 
 #if APPLE_IIE