https://github.com/akkartik/mu/blob/main/baremetal/501draw-text.mu
  1 # draw a single line of text from x, y to xmax
  2 # return the next 'x' coordinate
  3 # if there isn't enough space, return 0 without modifying the screen
  4 fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int -> _/eax: int {
  5   var stream-storage: (stream byte 0x100)
  6   var stream/esi: (addr stream byte) <- address stream-storage
  7   write stream, text
  8   # check if we have enough space
  9   var xcurr/ecx: int <- copy x
 10   {
 11     compare xcurr, xmax
 12     break-if->
 13     var g/eax: grapheme <- read-grapheme stream
 14     compare g, 0xffffffff  # end-of-file
 15     break-if-=
 16     xcurr <- add 8  # font-width
 17     loop
 18   }
 19   compare xcurr, xmax
 20   {
 21     break-if-<=
 22     return 0
 23   }
 24   # we do; actually draw
 25   rewind-stream stream
 26   xcurr <- copy x
 27   {
 28     var g/eax: grapheme <- read-grapheme stream
 29     compare g, 0xffffffff  # end-of-file
 30     break-if-=
 31     draw-grapheme screen, g, xcurr, y, color
 32     xcurr <- add 8  # font-width
 33     loop
 34   }
 35   set-cursor-position screen, xcurr, y
 36   return xcurr
 37 }
 38 
 39 fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int -> _/eax: int {
 40   var cursor-x/eax: int <- copy 0
 41   var cursor-y/ecx: int <- copy 0
 42   cursor-x, cursor-y <- cursor-position screen
 43   var result/eax: int <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color
 44   return result
 45 }
 46 
 47 # draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
 48 # return the next (x, y) coordinate in raster order where drawing stopped
 49 # that way the caller can draw more if given the same min and max bounding-box.
 50 # if there isn't enough space, return 0 without modifying the screen
 51 fn draw-text-wrapping-right-then-down 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 {
 52   var stream-storage: (stream byte 0x100)
 53   var stream/esi: (addr stream byte) <- address stream-storage
 54   write stream, text
 55   # check if we have enough space
 56   var xcurr/edx: int <- copy x
 57   var ycurr/ecx: int <- copy y
 58   {
 59     compare ycurr, ymax
 60     break-if->=
 61     var g/eax: grapheme <- read-grapheme stream
 62     compare g, 0xffffffff  # end-of-file
 63     break-if-=
 64     xcurr <- add 8  # font-width
 65     compare xcurr, xmax
 66     {
 67       break-if-<
 68       xcurr <- copy xmin
 69       ycurr <- add 0x10  # font-height
 70     }
 71     loop
 72   }
 73   compare ycurr, ymax
 74   {
 75     break-if-<
 76     return 0, 0
 77   }
 78   # we do; actually draw
 79   rewind-stream stream
 80   xcurr <- copy x
 81   ycurr <- copy y
 82   {
 83     var g/eax: grapheme <- read-grapheme stream
 84     compare g, 0xffffffff  # end-of-file
 85     break-if-=
 86     draw-grapheme screen, g, xcurr, ycurr, color
 87     xcurr <- add 8  # font-width
 88     compare xcurr, xmax
 89     {
 90       break-if-<
 91       xcurr <- copy xmin
 92       ycurr <- add 0x10  # font-height
 93     }
 94     loop
 95   }
 96   set-cursor-position screen, xcurr, ycurr
 97   return xcurr, ycurr
 98 }
 99 
100 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 {
101   var cursor-x/eax: int <- copy 0
102   var cursor-y/ecx: int <- copy 0
103   cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, 0, 0, 0x400, 0x300, x, y, color  # 1024, 768
104   return cursor-x, cursor-y
105 }
106 
107 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 {
108   var cursor-x/eax: int <- copy 0
109   var cursor-y/ecx: int <- copy 0
110   cursor-x, cursor-y <- cursor-position screen
111   var end-x/edx: int <- copy cursor-x
112   end-x <- add 8  # font-width
113   compare end-x, xmax
114   {
115     break-if-<
116     cursor-x <- copy xmin
117     cursor-y <- add 0x10  # font-height
118   }
119   cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color
120   return cursor-x, cursor-y
121 }
122 
123 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 {
124   var cursor-x/eax: int <- copy 0
125   var cursor-y/ecx: int <- copy 0
126   cursor-x, cursor-y <- draw-text-wrapping-right-then-down-from-cursor screen, text, 0, 0, 0x400, 0x300, color  # 1024, 768
127   return cursor-x, cursor-y
128 }
129 
130 ## Text direction: down then right
131 
132 # draw a single line of text vertically from x, y to ymax
133 # return the next 'y' coordinate
134 # if there isn't enough space, return 0 without modifying the screen
135 fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int -> _/eax: int {
136   var stream-storage: (stream byte 0x100)
137   var stream/esi: (addr stream byte) <- address stream-storage
138   write stream, text
139   # check if we have enough space
140   var ycurr/ecx: int <- copy y
141   {
142     compare ycurr, ymax
143     break-if->
144     var g/eax: grapheme <- read-grapheme stream
145     compare g, 0xffffffff  # end-of-file
146     break-if-=
147     ycurr <- add 0x10  # font-height
148     loop
149   }
150   compare ycurr, ymax
151   {
152     break-if-<=
153     return 0
154   }
155   # we do; actually draw
156   rewind-stream stream
157   ycurr <- copy y
158   {
159     var g/eax: grapheme <- read-grapheme stream
160     compare g, 0xffffffff  # end-of-file
161     break-if-=
162     draw-grapheme screen, g, x, ycurr, color
163     ycurr <- add 0x10  # font-height
164     loop
165   }
166   set-cursor-position screen, x, ycurr
167   return ycurr
168 }
169 
170 fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int -> _/eax: int {
171   var cursor-x/eax: int <- copy 0
172   var cursor-y/ecx: int <- copy 0
173   cursor-x, cursor-y <- cursor-position screen
174   var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color
175   return result
176 }
177 
178 # draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
179 # return the next (x, y) coordinate in raster order where drawing stopped
180 # that way the caller can draw more if given the same min and max bounding-box.
181 # if there isn't enough space, return 0 without modifying the screen
182 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 {
183   var stream-storage: (stream byte 0x100)
184   var stream/esi: (addr stream byte) <- address stream-storage
185   write stream, text
186   # check if we have enough space
187   var xcurr/edx: int <- copy x
188   var ycurr/ecx: int <- copy y
189   {
190     compare xcurr, xmax
191     break-if->=
192     var g/eax: grapheme <- read-grapheme stream
193     compare g, 0xffffffff  # end-of-file
194     break-if-=
195     ycurr <- add 0x10  # font-height
196     compare ycurr, ymax
197     {
198       break-if-<
199       xcurr <- add 8  # font-width
200       ycurr <- copy ymin
201     }
202     loop
203   }
204   compare xcurr, xmax
205   {
206     break-if-<
207     return 0, 0
208   }
209   # we do; actually draw
210   rewind-stream stream
211   xcurr <- copy x
212   ycurr <- copy y
213   {
214     var g/eax: grapheme <- read-grapheme stream
215     compare g, 0xffffffff  # end-of-file
216     break-if-=
217     draw-grapheme screen, g, xcurr, ycurr, color
218     ycurr <- add 0x10  # font-height
219     compare ycurr, ymax
220     {
221       break-if-<
222       xcurr <- add 8  # font-width
223       ycurr <- copy ymin
224     }
225     loop
226   }
227   set-cursor-position screen, xcurr, ycurr
228   return xcurr, ycurr
229 }
230 
231 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 {
232   var cursor-x/eax: int <- copy 0
233   var cursor-y/ecx: int <- copy 0
234   cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, 0, 0, 0x400, 0x300, x, y, color  # 1024, 768
235   return cursor-x, cursor-y
236 }
237 
238 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 {
239   var cursor-x/eax: int <- copy 0
240   var cursor-y/ecx: int <- copy 0
241   cursor-x, cursor-y <- cursor-position screen
242   var end-y/edx: int <- copy cursor-y
243   end-y <- add 0x10  # font-height
244   compare end-y, ymax
245   {
246     break-if-<
247     cursor-x <- add 8  # font-width
248     cursor-y <- copy ymin
249   }
250   cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color
251   return cursor-x, cursor-y
252 }
253 
254 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 {
255   var cursor-x/eax: int <- copy 0
256   var cursor-y/ecx: int <- copy 0
257   cursor-x, cursor-y <- draw-text-wrapping-down-then-right-from-cursor screen, text, 0, 0, 0x400, 0x300, color  # 1024, 768
258   return cursor-x, cursor-y
259 }