about summary refs log blame commit diff stats
path: root/501draw-text.mu
blob: 6102364226ab2c494f44c272b10256080332ab44 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11

                                                                        
                                           







                                              
                       
                                                

 
                                            


                                     

                                   


                                              
                         



              
                       
                                                

 
                                         







                                              
                       
                                                

 
                                           


                                      

                                    


                                              
                         



              
                       
                                                

 
                                                                  

















                                                






                                                                                                      
                                                                                                                       


                                              
                                                                                                
                                     



                                                    






                                                      

 

                                              
                                       
                                                                                                                                                   
                                                           

                                                              







                                                                                                                                                        
                              
   
                                               
                                     
              

                                                                                       
                       

        
                                      
              
 
 







                                                                                                                                                         
                                                                                                                                 


                                              

                                                                                                 

 






                                                                                                                                       
                                                                                                                                                                                    
                          
                        


                                    
                                                                                           



                  
                                                                                 
                 








                  
                                                                                                           
                                                                         
                                                                               
                                       
                                                                                                                                                                                                                  
                                                           


                                                              
                                      



                                                                                 
                                      



                      










                                                                                                                                                                                                                    

                              
                                 
                                      
                                               












                                                             
                                     
              






                                                                                                     
                                                     

                                                                                           






















                                                                                               






                        

        
                                          

                     
 





















                                                                                                                                                                                      



                                                                                   
                       



                         
                         
   
                                                

 
                                                                                                                                                                                    


                                               
                                                                                                                  
                                     

 
                                                                                                                                                                                 


                                              
                                     
                    



                         
                         
   
                                                                                                                                            

 
                                                                                                                                                      


                                     
                                                                                                                     

 
                                                                                                                                                                                                   


                                                              
                              
                              



                                               

                                                                                           
                       








                                          


                     
                                                                                                                                                                        


                                               
                                                                                                                    
                                     

 
                                                                                                                                                                     



                                              
                    



                         
                         
   
                                                                                                                                              

 
                                                                                                                                          


                                     
                                                                                                                       

 
                                                                                                                                                                                                       


                                                              





                                               

                                                                                           
                       








                                          


                     
                                                                                                                                                                            


                                               
                                                                                                                        
                                     

 
                                                                                                                                                                         



                                              
                    



                         
                         
   
                                                                                                                                                  

 
                                                                                                                                              


                                     
                                                                                                                           

 



                                                         
                                       
                                                                                                                                                  


                                                              






                                                                                                
                                         
                                                                                                                                                       

                              
                                               
                                     
              

                                                                                      
                      

        
                                      


              
                                                                                                                                


                                              
                                                                                                           




                                                                                                                          
                                       
                                                                                                                                                                                                                 


                                                              









                                                                                                                              
                                                                         
                                                                                                                                                                                                                    


                              
                                               
                                     
              

                                                                                           
                      


                       
                    



                        
                                          


                     
                                                                                                                                                                                    


                                               
                                                                                                                  
                                     

 
                                                                                                                                                                                 


                                              
                                     
                    


                     
                         

                         
                                                                                                                                            

 
                                                                                                                                                      


                                     
                                                                                                                     
 
# some primitives for moving the cursor without making assumptions about
# raster order
fn move-cursor-left screen: (addr screen) {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  compare cursor-x, 0
  {
    break-if->
    return
  }
  cursor-x <- decrement
  set-cursor-position screen, cursor-x, cursor-y
}

fn move-cursor-right screen: (addr screen) {
  var _width/eax: int <- copy 0
  var dummy/ecx: int <- copy 0
  _width, dummy <- screen-size screen
  var limit/edx: int <- copy _width
  limit <- decrement
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  compare cursor-x, limit
  {
    break-if-<
    return
  }
  cursor-x <- increment
  set-cursor-position screen, cursor-x, cursor-y
}

fn move-cursor-up screen: (addr screen) {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  compare cursor-y, 0
  {
    break-if->
    return
  }
  cursor-y <- decrement
  set-cursor-position screen, cursor-x, cursor-y
}

fn move-cursor-down screen: (addr screen) {
  var dummy/eax: int <- copy 0
  var _height/ecx: int <- copy 0
  dummy, _height <- screen-size screen
  var limit/edx: int <- copy _height
  limit <- decrement
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  compare cursor-y, limit
  {
    break-if-<
    return
  }
  cursor-y <- increment
  set-cursor-position screen, cursor-x, cursor-y
}

fn move-cursor-to-left-margin-of-next-line screen: (addr screen) {
  var dummy/eax: int <- copy 0
  var _height/ecx: int <- copy 0
  dummy, _height <- screen-size screen
  var limit/edx: int <- copy _height
  limit <- decrement
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  compare cursor-y, limit
  {
    break-if-<
    return
  }
  cursor-y <- increment
  cursor-x <- copy 0
  set-cursor-position screen, cursor-x, cursor-y
}

fn draw-code-point-at-cursor screen: (addr screen), c: code-point, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var dummy/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, color, background-color
}

fn draw-code-point-at-cursor-over-full-screen screen: (addr screen), c: code-point, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var _offset/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, color, background-color
  var offset/edx: int <- copy _offset
  var width/eax: int <- copy 0
  var dummy/ecx: int <- copy 0
  width, dummy <- screen-size screen
  move-cursor-rightward-and-downward screen, 0 width
  offset <- decrement
  compare offset, 0
  {
    break-if-=
    # should never move downward here
    move-cursor-rightward-and-downward screen, 0 width
  }
}

# draw a single line of text from x, y to xmax
# return the next 'x' coordinate
# if there isn't enough space, truncate
fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
  var stream-storage: (stream byte 0x400/print-buffer-size)
  var stream/esi: (addr stream byte) <- address stream-storage
  write stream, text
  var xcurr/eax: int <- draw-stream-rightward screen, stream, x, xmax, y, color, background-color
  return xcurr
}

# draw a single-line stream from x, y to xmax
# return the next 'x' coordinate
# if there isn't enough space, truncate
fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
  var xcurr/ecx: int <- copy x
  {
    var g/eax: grapheme <- read-grapheme stream
    compare g, 0xffffffff/end-of-file
    break-if-=
    var c/eax: code-point <- to-code-point g
    var offset/eax: int <- draw-code-point screen, c, xcurr, y, color, background-color
    xcurr <- add offset
    loop
  }
  set-cursor-position screen, xcurr, y
  return xcurr
}

fn draw-text-rightward-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  var result/eax: int <- draw-text-rightward screen, text, x, width, y, color, background-color
  return result
}

fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  cursor-x <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color, background-color
  set-cursor-position screen, cursor-x, cursor-y
}

fn draw-text-rightward-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-text-rightward-from-cursor screen, text, width, color, background-color
}

fn render-code-point screen: (addr screen), c: code-point, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var x/ecx: int <- copy x
  compare c, 0xa/newline
  {
    break-if-!=
    # minimum effort to clear cursor
    var dummy/eax: int <- draw-code-point screen, 0x20/space, x, y, color, background-color
    x <- copy xmin
    increment y
    return x, y
  }
  var offset/eax: int <- draw-code-point screen, c, x, y, color, background-color
  x <- add offset
  compare x, xmax
  {
    break-if-<
    x <- copy xmin
    increment y
  }
  return x, y
}

# 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.
# if there isn't enough space, truncate
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, background-color: int -> _/eax: int, _/ecx: int {
  var stream-storage: (stream byte 0x200/print-buffer-size)
  var stream/edi: (addr stream byte) <- address stream-storage
  var text/esi: (addr array byte) <- copy _text
  var len/eax: int <- length text
  compare len, 0x200/print-buffer-size
  {
    break-if-<
    write stream, "ERROR: stream too small in draw-text-wrapping-right-then-down"
  }
  compare len, 0x200/print-buffer-size
  {
    break-if->=
    write stream, text
  }
  var x/eax: int <- copy _x
  var y/ecx: int <- copy _y
  x, y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
  return x, y
}

# draw a stream 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, truncate
fn draw-stream-wrapping-right-then-down screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var xcurr/ecx: int <- copy x
  var ycurr/edx: int <- copy y
  var c/ebx: code-point <- copy 0
  var next-c/esi: code-point <- copy 0
  $draw-stream-wrapping-right-then-down:loop: {
    # read c from either next-c or stream
    $draw-stream-wrapping-right-then-down:read-base: {
      compare next-c, 0
      {
        break-if-=
        c <- copy next-c
        next-c <- copy 0
        break $draw-stream-wrapping-right-then-down:read-base
      }
      var g/eax: grapheme <- read-grapheme stream
      var _c/eax: code-point <- to-code-point g
      c <- copy _c
    }
    compare c, 0xffffffff/end-of-file
    break-if-=
    compare c, 0xa/newline
    {
      break-if-!=
      # minimum effort to clear cursor
      var dummy/eax: int <- draw-code-point screen, 0x20/space, xcurr, ycurr, color, background-color
      xcurr <- copy xmin
      ycurr <- increment
      loop $draw-stream-wrapping-right-then-down:loop
    }
    var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
    # overlay a combining character if necessary
    $draw-stream-wrapping-right-then-down:read-combiner: {
      var done?/eax: boolean <- stream-empty? stream
      compare done?, 0/false
      break-if-!=
      # read a character
      var g/eax: grapheme <- read-grapheme stream
      var c/eax: code-point <- to-code-point g
      # if not a combining character, save for next iteration and loop
      {
        var combining-code-point?/eax: boolean <- combining-code-point? c
        compare combining-code-point?, 0/false
      }
      {
        break-if-!=
        next-c <- copy c
        break $draw-stream-wrapping-right-then-down:read-combiner
      }
      # otherwise overlay it without saving its width
      # This means strange results if a base and its combiner have different
      # widths. We'll always follow the base width.
      var dummy/eax: int <- overlay-code-point screen, c, xcurr, ycurr, color, background-color
    }
    xcurr <- add offset
    compare xcurr, xmax
    {
      break-if-<
      xcurr <- copy xmin
      ycurr <- increment
    }
    loop
  }
  set-cursor-position screen, xcurr, ycurr
  return xcurr, ycurr
}

fn draw-stream-wrapping-right-then-down-from-cursor screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var end-x/edx: int <- copy cursor-x
  end-x <- increment
  compare end-x, xmax
  {
    break-if-<
    cursor-x <- copy xmin
    cursor-y <- increment
  }
  cursor-x, cursor-y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
}

fn draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), stream: (addr stream byte), color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-stream-wrapping-right-then-down-from-cursor screen, stream, 0/xmin, 0/ymin, width, height, color, background-color
}

fn move-cursor-rightward-and-downward screen: (addr screen), xmin: int, xmax: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  cursor-x <- increment
  compare cursor-x, xmax
  {
    break-if-<
    cursor-x <- copy xmin
    cursor-y <- increment
  }
  set-cursor-position screen, cursor-x, cursor-y
}

fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var x2/eax: int <- copy 0
  var y2/ecx: int <- copy 0
  x2, y2 <- screen-size screen  # width, height
  x2, y2 <- draw-text-wrapping-right-then-down screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
  return x2, y2  # 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, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var end-x/edx: int <- copy cursor-x
  end-x <- increment
  compare end-x, xmax
  {
    break-if-<
    cursor-x <- copy xmin
    cursor-y <- increment
  }
  cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
}

fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-text-wrapping-right-then-down-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
}

fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var stream-storage: (stream byte 0x100)
  var stream/esi: (addr stream byte) <- address stream-storage
  write-int32-hex stream, n
  var xcurr/edx: int <- copy x
  var ycurr/ecx: int <- copy y
  {
    var g/eax: grapheme <- read-grapheme stream
    compare g, 0xffffffff/end-of-file
    break-if-=
    var c/eax: code-point <- to-code-point g
    var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
    xcurr <- add offset
    compare xcurr, xmax
    {
      break-if-<
      xcurr <- copy xmin
      ycurr <- increment
    }
    loop
  }
  set-cursor-position screen, xcurr, ycurr
  return xcurr, ycurr
}

fn draw-int32-hex-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var x2/eax: int <- copy 0
  var y2/ecx: int <- copy 0
  x2, y2 <- screen-size screen  # width, height
  x2, y2 <- draw-int32-hex-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
  return x2, y2  # cursor-x, cursor-y
}

fn draw-int32-hex-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var end-x/edx: int <- copy cursor-x
  end-x <- increment
  compare end-x, xmax
  {
    break-if-<
    cursor-x <- copy xmin
    cursor-y <- increment
  }
  cursor-x, cursor-y <- draw-int32-hex-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
}

fn draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-int32-hex-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
}

fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var stream-storage: (stream byte 0x100)
  var stream/esi: (addr stream byte) <- address stream-storage
  write-int32-decimal stream, n
  var xcurr/edx: int <- copy x
  var ycurr/ecx: int <- copy y
  {
    var g/eax: grapheme <- read-grapheme stream
    compare g, 0xffffffff/end-of-file
    break-if-=
    var c/eax: code-point <- to-code-point g
    var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
    xcurr <- add offset
    compare xcurr, xmax
    {
      break-if-<
      xcurr <- copy xmin
      ycurr <- increment
    }
    loop
  }
  set-cursor-position screen, xcurr, ycurr
  return xcurr, ycurr
}

fn draw-int32-decimal-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var x2/eax: int <- copy 0
  var y2/ecx: int <- copy 0
  x2, y2 <- screen-size screen  # width, height
  x2, y2 <- draw-int32-decimal-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
  return x2, y2  # cursor-x, cursor-y
}

fn draw-int32-decimal-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
  var cursor-x/eax: int <- copy 0
  var cursor-y/ecx: int <- copy 0
  cursor-x, cursor-y <- cursor-position screen
  var end-x/edx: int <- copy cursor-x
  end-x <- increment
  compare end-x, xmax
  {
    break-if-<
    cursor-x <- copy xmin
    cursor-y <- increment
  }
  cursor-x, cursor-y <- draw-int32-decimal-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
}

fn draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-int32-decimal-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
}

## 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, truncate
fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
  var stream-storage: (stream byte 0x100)
  var stream/esi: (addr stream byte) <- address stream-storage
  write stream, text
  var ycurr/eax: int <- draw-stream-downward screen, stream, x, y, ymax, color, background-color
  return ycurr
}

# draw a single-line stream vertically from x, y to ymax
# return the next 'y' coordinate
# if there isn't enough space, truncate
# TODO: should we track horizontal width?
fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
  var ycurr/ecx: int <- copy y
  {
    var g/eax: grapheme <- read-grapheme stream
    compare g, 0xffffffff/end-of-file
    break-if-=
    var c/eax: code-point <- to-code-point g
    var dummy/eax: int <- draw-code-point screen, c, x, ycurr, color, background-color
    ycurr <- increment
    loop
  }
  set-cursor-position screen, x, ycurr
  return ycurr
}

fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int, background-color: 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, background-color
}

# 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, truncate
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, background-color: int -> _/eax: int, _/ecx: int {
  var stream-storage: (stream byte 0x100)
  var stream/esi: (addr stream byte) <- address stream-storage
  write stream, text
  var x/eax: int <- copy _x
  var y/ecx: int <- copy _y
  x, y <- draw-stream-wrapping-down-then-right screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
  return x, y
}

# draw a stream 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, truncate
# TODO: should we track horizontal width? just always offset by 2 for now
fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
  var xcurr/edx: int <- copy x
  var ycurr/ecx: int <- copy y
  {
    var g/eax: grapheme <- read-grapheme stream
    compare g, 0xffffffff/end-of-file
    break-if-=
    var c/eax: code-point <- to-code-point g
    var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
    ycurr <- increment
    compare ycurr, ymax
    {
      break-if-<
      xcurr <- add 2
      ycurr <- copy ymin
    }
    loop
  }
  set-cursor-position screen, xcurr, ycurr
  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, background-color: int -> _/eax: int, _/ecx: int {
  var x2/eax: int <- copy 0
  var y2/ecx: int <- copy 0
  x2, y2 <- screen-size screen  # width, height
  x2, y2 <- draw-text-wrapping-down-then-right screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
  return x2, y2  # 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, background-color: 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 <- increment
  compare end-y, ymax
  {
    break-if-<
    cursor-x <- increment
    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, background-color
}

fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
  var width/eax: int <- copy 0
  var height/ecx: int <- copy 0
  width, height <- screen-size screen
  draw-text-wrapping-down-then-right-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
}