about summary refs log tree commit diff stats
path: root/103glyph.subx
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-08-29 22:16:34 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-08-29 22:20:09 -0700
commit6e05a8fa27139ddf75a029ad94d44b48a92785b2 (patch)
tree8d04ae5d057030246305c9dc4b46fb2fe176f643 /103glyph.subx
parent4b90a26d71513f3b908b7f7ec651996ddf6460d6 (diff)
downloadmu-6e05a8fa27139ddf75a029ad94d44b48a92785b2.tar.gz
fix bad terminology: grapheme -> code point
Unix text-mode terminals transparently support utf-8 these days, and so
I treat utf-8 sequences (which I call graphemes in Mu) as fundamental.

I then blindly carried over this state of affairs to bare-metal Mu,
where it makes no sense. If you don't have a terminal handling
font-rendering for you, fonts are most often indexed by code points and
not utf-8 sequences.
Diffstat (limited to '103glyph.subx')
-rw-r--r--103glyph.subx365
1 files changed, 365 insertions, 0 deletions
diff --git a/103glyph.subx b/103glyph.subx
new file mode 100644
index 00000000..61035f22
--- /dev/null
+++ b/103glyph.subx
@@ -0,0 +1,365 @@
+# Use the built-in font to draw glyphs to screen.
+#   https://en.wikipedia.org/wiki/Glyph#Typography
+# The Mu computer can currently only render glyphs corresponding to single
+# code points. No combining characters.
+#   https://en.wikipedia.org/wiki/Code_point
+#   https://en.wikipedia.org/wiki/Combining_character
+#
+# We need to do this in machine code because Mu doesn't have global variables
+# yet (for the start of the font).
+
+== code
+
+# The Mu computer's screen is 1024px wide and 768px tall.
+# The Mu computer's font is 8px wide and 16px tall.
+# Therefore 'x' here is in [0, 128), and 'y' is in [0, 48)
+# Doesn't update the cursor; where the cursor should go after printing the
+# current code-point is a higher-level concern.
+draw-code-point-on-real-screen:  # c: code-point, x: int, y: int, color: int, background-color: int -> _/eax
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    #
+    (draw-code-point-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 0x80 0x30)  # => eax
+$draw-code-point-on-real-screen:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+draw-code-point-on-screen-array:  # screen-data: (addr array byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    51/push-ecx
+    52/push-edx
+    # if screen-width*screen-height > len(screen-data) abort
+    {
+      # ecx = len(screen-data)
+      8b/-> *(ebp+8) 1/r32/ecx
+      8b/-> *ecx 1/r32/ecx
+      # eax = screen-width*screen-height
+      ba/copy-to-edx 0/imm32
+      8b/-> *(ebp+0x20) 0/r32/eax
+      f7 4/subop/multiply-into-eax *(ebp+0x24)
+      81 7/subop/compare %edx 0/imm32
+      0f 85/jump-if-!= $draw-code-point-on-screen-array:overflow/disp32
+      # if (eax > ecx) abort
+      39/compare %eax 1/r32/ecx
+      0f 8f/jump-if-> $draw-code-point-on-screen-array:abort/disp32
+    }
+    # eax = screen-data+4   (skip length)
+    8b/-> *(ebp+8) 0/r32/eax
+    05/add-to-eax 4/imm32
+    #
+    (draw-code-point-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))  # => eax
+$draw-code-point-on-screen-array:end:
+    # . restore registers
+    5a/pop-to-edx
+    59/pop-to-ecx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+$draw-code-point-on-screen-array:overflow:
+    (abort "draw-code-point-on-screen-array: screen dimensions too large")
+
+$draw-code-point-on-screen-array:abort:
+    (abort "draw-code-point-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
+
+# 'buffer' here is not a valid Mu type: a naked address without a length.
+# returns number of 8x16 units printed to screen (1 or 2).
+draw-code-point-on-screen-buffer:  # buffer: (addr byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    56/push-esi
+    # switch screen-width and screen-height from code-point to pixel units
+    c1 4/subop/shift-left *(ebp+20) 3/imm8/log2-font-width
+    c1 4/subop/shift-left *(ebp+24) 4/imm8/log2-font-height
+    # esi = c
+    8b/-> *(ebp+0xc) 6/r32/esi
+    # if (c >= 4352) return  # unicode planes supported: latin, greek, cyrillic, armenian, hebrew, arabic, syriac, thaana, n'ko, indian (iscii), sinhala, thai, lao, tibetan, myanmar, georgian
+                             # next few to support: CJK, ethiopic, cherokee, ...
+    81 7/subop/compare %esi 0x1100/imm32
+    0f 8d/jump-if->= $draw-code-point-on-screen-buffer:end/disp32
+    # var letter-bitmap/esi = font[c]
+    69/multiply %esi 0x21/imm32/glyph-size 6/r32/esi
+    81 0/subop/add %esi 0x0010000c/imm32/Font  # see boot.subx
+    # dispatch based on letter-bitmap->size
+    b8/copy-to-eax 0/imm32
+    8a/byte-> *esi 0/r32/AL
+    46/increment-esi  # skip size
+    3d/compare-eax-and 8/imm32
+    {
+      75/jump-if-!= break/disp8
+      (draw-narrow-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+      b8/copy-to-eax 1/imm32
+      eb/jump $draw-code-point-on-screen-buffer:end/disp8
+    }
+    (draw-wide-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+    b8/copy-to-eax 2/imm32
+$draw-code-point-on-screen-buffer:end:
+    # . restore registers
+    5e/pop-to-esi
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+wide-code-point?:  # c: code-point -> _/eax: boolean
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # eax = c
+    8b/-> *(ebp+8) 0/r32/eax
+    # if (c >= 128) return  # characters beyond ASCII currently not supported
+    3d/compare-eax-and 0x80/imm32
+    0f 8d/jump-if->= $wide-code-point?:end/disp32
+    # var letter-bitmap/eax = font[c]
+    69/multiply %eax 0x21/imm32/glyph-size 0/r32/eax
+    05/add-to-eax 0x0010000c/imm32/Font  # see boot.subx
+    # dispatch based on letter-bitmap->size
+    8a/byte-> *eax 0/r32/AL
+    25/and-eax-with  0xff/imm32
+    3d/compare-eax-and 8/imm32
+    0f 95/set-if-!= %eax
+$wide-code-point?:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+# buffer: naked address to raw screen RAM without a length
+# letter-bitmap: naked address to 8-pixel wide font glyph
+draw-narrow-code-point-on-screen-buffer:  # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    52/push-edx
+    53/push-ebx
+    56/push-esi
+    57/push-edi
+    # esi = letter-bitmap
+    8b/-> *(ebp+0xc) 6/r32/esi
+    # var ycurr/edx: int = y*16
+    8b/-> *(ebp+0x14) 2/r32/edx
+    c1 4/subop/shift-left %edx 4/imm8
+    # var ymax/edi: int = ycurr + 16
+    8b/-> *(ebp+0x14) 7/r32/edi
+    c1 4/subop/shift-left %edi 4/imm8
+    81 0/subop/add %edi 0x10/imm32
+    {
+      # if (ycurr >= ymax) break
+      39/compare %edx 7/r32/edi
+      0f 8d/jump-if->= break/disp32
+      # var row-bitmap/ebx: byte = *letter-bitmap
+      bb/copy-to-ebx 0/imm32
+      8a/byte-> *esi 3/r32/BL
+      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx *(ebp+0x10) %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+      # ++y
+      42/increment-edx
+      # next bitmap row
+      46/increment-esi
+      #
+      e9/jump loop/disp32
+    }
+$draw-narrow-code-point-on-screen-buffer:end:
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    5b/pop-to-ebx
+    5a/pop-to-edx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+# buffer: naked address to raw screen RAM without a length
+# letter-bitmap: naked address to 16-pixel wide font glyph
+draw-wide-code-point-on-screen-buffer:  # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    53/push-ebx
+    56/push-esi
+    57/push-edi
+    # esi = letter-bitmap
+    8b/-> *(ebp+0xc) 6/r32/esi
+    #
+    bb/copy-to-ebx 0/imm32
+    # var ycurr/edx: int = y*16
+    8b/-> *(ebp+0x14) 2/r32/edx
+    c1 4/subop/shift-left %edx 4/imm8
+    # var ymax/edi: int = ycurr + 16
+    8b/-> *(ebp+0x14) 7/r32/edi
+    c1 4/subop/shift-left %edi 4/imm8
+    81 0/subop/add %edi 0x10/imm32
+    {
+      # if (ycurr >= ymax) break
+      39/compare %edx 7/r32/edi
+      0f 8d/jump-if->= break/disp32
+      # var row-bitmap/ebx: byte = *letter-bitmap
+      8a/byte-> *(esi+1) 3/r32/BL
+      # ecx = x
+      8b/-> *(ebp+0x10) 1/r32/ecx
+      # first half-row
+      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+      # second half-row
+      8a/byte-> *esi 3/r32/BL
+      49/increment-ecx
+      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+      # ++y
+      42/increment-edx
+      # next bitmap row
+      81 0/subop/add %esi 2/imm32
+      #
+      e9/jump loop/disp32
+    }
+$draw-wide-code-point-on-screen-buffer:end:
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    5b/pop-to-ebx
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+# draw 8 pixels from a single glyph byte in a font bitmap
+draw-run-of-pixels-from-glyph:  # buffer: (addr byte), glyph-byte: byte, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    56/push-esi
+    # esi = glyph-byte
+    8b/-> *(ebp+0xc) 6/r32/esi
+    # var xcurr/eax: int = x*8 + 7
+    8b/-> *(ebp+0x10) 0/r32/eax
+    c1 4/subop/shift-left %eax 3/imm8
+    05/add-to-eax 7/imm32
+    # var xmin/ecx: int = x*8
+    8b/-> *(ebp+0x10) 1/r32/ecx
+    c1 4/subop/shift-left %ecx 3/imm8
+    {
+      # if (xcurr < xmin) break
+      39/compare %eax 1/r32/ecx
+      7c/jump-if-< break/disp8
+      # shift LSB from row-bitmap into carry flag (CF)
+      c1 5/subop/shift-right-logical %esi 1/imm8
+      # if LSB, draw a pixel in the given color
+      {
+        73/jump-if-not-CF break/disp8
+        (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18) *(ebp+0x20) *(ebp+0x24))
+        eb/jump $draw-code-point-on-screen-buffer:continue/disp8
+      }
+      # otherwise use the background color
+      (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+$draw-code-point-on-screen-buffer:continue:
+      # --x
+      48/decrement-eax
+      #
+      eb/jump loop/disp8
+    }
+$draw-run-of-pixels-from-glyph:end:
+    # . restore registers
+    5e/pop-to-esi
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+cursor-position-on-real-screen:  # -> _/eax: int, _/ecx: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
+    8b/-> *Real-screen-cursor-x 0/r32/eax
+    8b/-> *Real-screen-cursor-y 1/r32/ecx
+$cursor-position-on-real-screen:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+set-cursor-position-on-real-screen:  # x: int, y: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    #
+    8b/-> *(ebp+8) 0/r32/eax
+    89/<- *Real-screen-cursor-x 0/r32/eax
+    8b/-> *(ebp+0xc) 0/r32/eax
+    89/<- *Real-screen-cursor-y 0/r32/eax
+$set-cursor-position-on-real-screen:end:
+    # . restore registers
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+# Not a real `show-cursor` primitive:
+#   - does not clear previous location cursor was shown at.
+#   - does not preserve what was at the cursor. Caller is responsible for
+#     tracking what was on the screen at this position before and passing it
+#     in again.
+#   - does not stop showing the cursor at this location when the cursor moves
+draw-cursor-on-real-screen:  # c: code-point
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    #
+    (cursor-position-on-real-screen)  # => eax, ecx
+    (draw-code-point-on-real-screen *(ebp+8) %eax %ecx 0 7)  # => eax
+$draw-cursor-on-real-screen:end:
+    # . restore registers
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+== data
+
+# The cursor is where certain Mu functions (usually of the form
+# 'draw*cursor*') print to by default.
+#
+# We don't bother displaying the cursor when drawing. It only becomes visible
+# on draw-cursor, which is quite rickety (see above)
+#
+# It's up to applications to manage cursor display:
+#   - clean up where it used to be
+#   - display the cursor before waiting for a key
+#   - ensure its location appropriately suggests the effect keystrokes will have
+#   - ensure its contents (and colors) appropriately reflect the state of the
+#     screen
+#
+# There's no blinking, etc. We aren't using any hardware-supported text mode
+# here.
+Real-screen-cursor-x:
+  0/imm32
+Real-screen-cursor-y:
+  0/imm32