Implement a new gr_encode() routine containing most of the logic of gr_update()
authorNick Downing <nick@ndcode.org>
Tue, 24 May 2022 03:20:24 +0000 (13:20 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 24 May 2022 03:20:24 +0000 (13:20 +1000)
apple_io.py
applesoft_basic.py

index da8144e..9b6b7d7 100644 (file)
@@ -201,7 +201,6 @@ BEEP_STYLE_ALSA = 0
 BEEP_STYLE_VT100 = 1
 
 beep_style = BEEP_STYLE_ALSA
-gr_width = 1
 
 # global state
 termios_attr = None
@@ -571,47 +570,49 @@ def gr():
     addr = bascalc(i)
     low_mem[addr:addr + 40] = [0] * 40
 
+# takes memory encoded with upper pixel in bits 0-3, lower in bits 4-7
+# returns a stream of unicode characters with attribute-setting escapes
+# attribute-setting can be optimized by passing in a previous attribute
+def gr_encode(_in, attr = (-1, -1, -1)):
+  out = []
+  for i in _in:
+    background = colors[i & 0xf]
+    foreground = colors[i >> 4]
+    # we cannot draw two different intense colours in same block,
+    # so just do the best we can (the greater colour gets priority)
+    if background < foreground:
+      ch = '▄'
+    elif background > foreground:
+      background, foreground = foreground, background
+      ch = '▀'
+    elif background < 8:
+      # we try to draw not-intense pixels using background, it
+      # might play nicer with terminals that use black-on-white
+      foreground = 0
+      ch = ' '
+    else:
+      background = 0
+      ch = '█'
+    new_attr = (background & 7, foreground & 7, foreground >> 3)
+    if new_attr != attr:
+      out.append(
+        '\x1b[0;{0:d};{1:d}{2:s}m'.format(
+          new_attr[0] + 40,
+          new_attr[1] + 30,
+          ';1' if new_attr[2] else ''
+        )
+      )
+      attr = new_attr
+    out.append(ch)
+  return ''.join(out), attr
+
 def gr_update(x0, y0, x1, y1):
   write('\x1b[s') # save cursor
-  bg = -1
-  fg = -1
-  br = -1
+  attr = (-1, -1, -1)
   for i in range(y0, y1):
-    write(f'\x1b[{i + 1:d};{x0 * gr_width + 1:d}H')
     addr = bascalc(i)
-    for j in range(x0, x1):
-      new_bg = colors[low_mem[addr + j] & 0xf]
-      new_fg = colors[low_mem[addr + j] >> 4]
-      # we cannot draw two different intense colours in same block,
-      # so just do the best we can (the greater colour gets priority)
-      if new_bg < new_fg:
-        ch = '▄'
-      elif new_bg > new_fg:
-        new_bg, new_fg = new_fg, new_bg
-        ch = '▀'
-      elif new_bg < 8:
-        # we try to draw not-intense pixels using background, it
-        # might play nicer with terminals that use black-on-white
-        new_fg = 0
-        ch = ' '
-      else:
-        new_bg = 0
-        ch = '█'
-      new_br = new_fg >= 8
-      new_bg &= 7
-      new_fg &= 7
-      if new_bg != bg or new_fg != fg or new_br != br:
-        write(
-          '\x1b[0{0:s}{1:s}{2:s}m'.format(
-            f';4{new_bg:d}' if new_bg else '',
-            f';3{new_fg:d}' if new_fg else '',
-            ';1' if new_br else ''
-          )
-        )
-        bg = new_bg
-        fg = new_fg
-        br = new_br
-      write(ch * gr_width)
+    data, attr = gr_encode(low_mem[addr + x0:addr + x1], attr)
+    write(f'\x1b[{i + 1:d};{x0 + 1:d}H{data:s}')
   write('\x1b[u') # restore cursor
   invflg() # restore normal/inverse/flash
 
index 92d7dfd..13e79ab 100755 (executable)
@@ -39,15 +39,13 @@ beep_styles = {
 while len(sys.argv) >= 2:
   if sys.argv[1][:7] == '--beep-style=':
     apple_io.beep_style = beep_styles[sys.arg[1][7:]]
-  elif sys.argv[1][:11] == '--gr-width=':
-    apple_io.gr_width = int(sys.argv[1][11:])
   elif sys.argv[1][:11] == '--joystick=':
     apple_joystick.input_path = sys.argv[1][11:]
   else:
     break
   del sys.argv[1]
 if len(sys.argv) < 2:
-  print(f'usage: {sys.argv[0]:s} [--beep-style=alsa|vt100] [--gr-width=n] [--joystick=/dev/input/eventNN] program.tok')
+  print(f'usage: {sys.argv[0]:s} [--beep-style=alsa|vt100] [--joystick=/dev/input/eventNN] program.tok')
   sys.exit(EXIT_FAILURE)
 program_bas = sys.argv[1]