diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-08-29 22:16:34 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-08-29 22:20:09 -0700 |
commit | 6e05a8fa27139ddf75a029ad94d44b48a92785b2 (patch) | |
tree | 8d04ae5d057030246305c9dc4b46fb2fe176f643 /103glyph.subx | |
parent | 4b90a26d71513f3b908b7f7ec651996ddf6460d6 (diff) | |
download | mu-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.subx | 365 |
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 |