From 4413168269ad3d3f31fdc60669bb812f54a3d01e Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 12 Jan 2021 23:52:24 -0800 Subject: [PATCH] 7507 - baremetal: drawing text down then right --- baremetal/103grapheme.subx | 28 ++++++ baremetal/400.mu | 1 + baremetal/501draw-text.mu | 169 +++++++++++++++++++++++++++++++++++++ baremetal/ex6.mu | 7 +- 4 files changed, 204 insertions(+), 1 deletion(-) diff --git a/baremetal/103grapheme.subx b/baremetal/103grapheme.subx index 934aac51..053cd497 100644 --- a/baremetal/103grapheme.subx +++ b/baremetal/103grapheme.subx @@ -8,6 +8,7 @@ draw-grapheme: # screen: (addr screen), g: grapheme, x: int, y: int, color: int 52/push-edx 53/push-ebx 56/push-esi + # TODO: support fake screen; we currently assume 'screen' is always 0 (real) # var letter-bitmap/esi = font[g] 8b/-> *(ebp+0xc) 6/r32/esi c1 4/subop/shift-left %esi 4/imm8 @@ -57,6 +58,12 @@ draw-grapheme: # screen: (addr screen), g: grapheme, x: int, y: int, color: int # eb/jump loop/disp8 } + # Save default coordinates for a future call to draw-grapheme + 8b/-> *(ebp+0x10) 0/r32/eax + 81 0/subop/add %eax 8/imm32 + 89/<- *Default-next-x 0/r32/eax + 8b/-> *(ebp+0x14) 0/r32/eax + 89/<- *Default-next-y 0/r32/eax $draw-grapheme:end: # . restore registers 5e/pop-to-esi @@ -68,3 +75,24 @@ $draw-grapheme:end: 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return + +cursor-position: # screen: (addr 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/-> *Default-next-x 0/r32/eax + 8b/-> *Default-next-y 1/r32/ecx +$cursor-position:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +== data + +Default-next-x: + 0/imm32 + +Default-next-y: + 0/imm32 diff --git a/baremetal/400.mu b/baremetal/400.mu index 2adb3254..c32497b8 100644 --- a/baremetal/400.mu +++ b/baremetal/400.mu @@ -1,6 +1,7 @@ sig pixel screen: (addr screen), x: int, y: int, color: int sig read-key kbd: (addr keyboard) -> _/eax: byte sig draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int +sig cursor-position screen: (addr screen) -> _/eax: int, _/ecx: int sig clear-stream f: (addr stream _) sig rewind-stream f: (addr stream _) sig write f: (addr stream byte), s: (addr array byte) diff --git a/baremetal/501draw-text.mu b/baremetal/501draw-text.mu index 0f091952..63e41728 100644 --- a/baremetal/501draw-text.mu +++ b/baremetal/501draw-text.mu @@ -35,6 +35,14 @@ fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, x return xcurr } +fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int -> _/eax: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- cursor-position screen + var result/eax: int <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color + return result +} + # draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary # return the next (x, y) coordinate in raster order where drawing stopped # that way the caller can draw more if given the same min and max bounding-box. @@ -86,3 +94,164 @@ fn draw-text-wrapping-right-then-down screen: (addr screen), text: (addr array b } return xcurr, ycurr } + +fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, 0, 0, 0x400, 0x300, x, y, color # 1024, 768 + return cursor-x, cursor-y +} + +fn draw-text-wrapping-right-then-down-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- cursor-position screen + # we could wrap around if we're too far to the right, but that feels like it + # makes assumptions about text direction +#? var end-x/edx: int <- copy cursor-x +#? end-x <- add 8 # font-width +#? compare end-x, xmax +#? { +#? break-if-< +#? cursor-x <- copy xmin +#? cursor-y <- add 0x10 # font-height +#? } + cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color + return cursor-x, cursor-y +} + +fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- draw-text-wrapping-right-then-down-from-cursor screen, text, 0, 0, 0x400, 0x300, color # 1024, 768 + return cursor-x, cursor-y +} + +## Text direction: down then right + +# draw a single line of text vertically from x, y to ymax +# return the next 'y' coordinate +# if there isn't enough space, return 0 without modifying the screen +fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int -> _/eax: int { + var stream-storage: (stream byte 0x100) + var stream/esi: (addr stream byte) <- address stream-storage + write stream, text + # check if we have enough space + var ycurr/ecx: int <- copy y + { + compare ycurr, ymax + break-if-> + var g/eax: grapheme <- read-grapheme stream + compare g, 0xffffffff # end-of-file + break-if-= + ycurr <- add 0x10 # font-height + loop + } + compare ycurr, ymax + { + break-if-<= + return 0 + } + # we do; actually draw + rewind-stream stream + ycurr <- copy y + { + var g/eax: grapheme <- read-grapheme stream + compare g, 0xffffffff # end-of-file + break-if-= + draw-grapheme screen, g, x, ycurr, color + ycurr <- add 0x10 # font-height + loop + } + return ycurr +} + +fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int -> _/eax: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- cursor-position screen + var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color + return result +} + +# draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary +# return the next (x, y) coordinate in raster order where drawing stopped +# that way the caller can draw more if given the same min and max bounding-box. +# if there isn't enough space, return 0 without modifying the screen +fn draw-text-wrapping-down-then-right screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int -> _/eax: int, _/ecx: int { + var stream-storage: (stream byte 0x100) + var stream/esi: (addr stream byte) <- address stream-storage + write stream, text + # check if we have enough space + var xcurr/edx: int <- copy x + var ycurr/ecx: int <- copy y + { + compare xcurr, xmax + break-if->= + var g/eax: grapheme <- read-grapheme stream + compare g, 0xffffffff # end-of-file + break-if-= + ycurr <- add 0x10 # font-height + compare ycurr, ymax + { + break-if-< + xcurr <- add 8 # font-width + ycurr <- copy ymin + } + loop + } + compare xcurr, xmax + { + break-if-< + return 0, 0 + } + # we do; actually draw + rewind-stream stream + xcurr <- copy x + ycurr <- copy y + { + var g/eax: grapheme <- read-grapheme stream + compare g, 0xffffffff # end-of-file + break-if-= + draw-grapheme screen, g, xcurr, ycurr, color + ycurr <- add 0x10 # font-height + compare ycurr, ymax + { + break-if-< + xcurr <- add 8 # font-width + ycurr <- copy ymin + } + loop + } + return xcurr, ycurr +} + +fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, 0, 0, 0x400, 0x300, x, y, color # 1024, 768 + return cursor-x, cursor-y +} + +fn draw-text-wrapping-down-then-right-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- cursor-position screen +#? var end-y/edx: int <- copy cursor-y +#? end-y <- add 0x10 # font-height +#? compare end-y, ymax +#? { +#? break-if-< +#? cursor-x <- add 8 # font-width +#? cursor-y <- copy ymin +#? } + cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color + return cursor-x, cursor-y +} + +fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int -> _/eax: int, _/ecx: int { + var cursor-x/eax: int <- copy 0 + var cursor-y/ecx: int <- copy 0 + cursor-x, cursor-y <- draw-text-wrapping-down-then-right-from-cursor screen, text, 0, 0, 0x400, 0x300, color # 1024, 768 + return cursor-x, cursor-y +} diff --git a/baremetal/ex6.mu b/baremetal/ex6.mu index 21922dab..00fefe60 100644 --- a/baremetal/ex6.mu +++ b/baremetal/ex6.mu @@ -1,4 +1,4 @@ -# Drawing ASCII text incrementally within a bounding box. +# Drawing ASCII text incrementally. # # To build a disk image: # ./translate_mu_baremetal baremetal/ex6.mu # emits disk.img @@ -10,6 +10,7 @@ # Expected output: a box and text that doesn't overflow it fn main { + # drawing text within a bounding box draw-box 0, 0xf, 0x1f, 0x79, 0x51, 0x4 var x/eax: int <- copy 0x20 var y/ecx: int <- copy 0x20 @@ -17,4 +18,8 @@ fn main { x, y <- draw-text-wrapping-right-then-down 0, "from ", 0x10, 0x20, 0x78, 0x50, x, y, 0xa x, y <- draw-text-wrapping-right-then-down 0, "baremetal ", 0x10, 0x20, 0x78, 0x50, x, y, 0xa x, y <- draw-text-wrapping-right-then-down 0, "Mu!", 0x10, 0x20, 0x78, 0x50, x, y, 0xa + + # drawing at the cursor in multiple directions + x, y <- draw-text-wrapping-down-then-right-from-cursor-over-full-screen 0, "abc", 0xa + x, y <- draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "def", 0xa }