about summary refs log tree commit diff stats
path: root/baremetal
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2021-01-12 23:52:24 -0800
committerKartik Agaram <vc@akkartik.com>2021-01-12 23:52:24 -0800
commit4413168269ad3d3f31fdc60669bb812f54a3d01e (patch)
treeb9b3c6e7b0852b332f6facf3e8501b44d7dc4050 /baremetal
parent8a81faecbe3c4bb2dbcbfc427f694b7932a1c5e5 (diff)
downloadmu-4413168269ad3d3f31fdc60669bb812f54a3d01e.tar.gz
7507 - baremetal: drawing text down then right
Diffstat (limited to 'baremetal')
-rw-r--r--baremetal/103grapheme.subx28
-rw-r--r--baremetal/400.mu1
-rw-r--r--baremetal/501draw-text.mu169
-rw-r--r--baremetal/ex6.mu7
4 files changed, 204 insertions, 1 deletions
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
 }